Я понял, как решить эту проблему, структура этих компонентов является иерархической, и я передал модель каждого компонента через @Input (), проблема в том, что первоначальный запрос асинхронный, и компоненты отображаются перед получением реального родителя.объект и после получения родительского объекта от сервера нет ссылки на объект для переданных объектов ввода, поэтому они не получат изменения.
Итак, как мы можем решить эту проблему?просто!удалить все входы и использовать программирование на основе событий. Как?создайте событие для каждого объекта или одно событие для родительского (корневого) объекта, от которого зависят все другие объекты, поделитесь событием в глобальной службе, инициируйте / отправьте событие, как только вы получите корневой объект, и подпишитесь на это событие в дочерних компонентах.позвольте мне показать вам простой фрагмент ниже:
import { HttpClient, HttpParams, HttpErrorResponse } from '@angular/common/http';
import { Injectable, EventEmitter } from '@angular/core';
import { Observable, throwError } from 'rxjs';
import { catchError } from 'rxjs/operators';
import { RootDto } from 'src/app/model/root.dto.model';
@Injectable()
export class CoreApiService {
public onDataReceived: EventEmitter<RootDto> = new EventEmitter<RootDto>();
constructor(private http: HttpClient) {
}
public getRootObject(objectId: number): Observable<RootDto> {
// const _params = new HttpParams().set('objectId', objectId);
return this.http
.get<RootDto>(`${Constants.ApiUrl}/root/${objectId}`)
.pipe(catchError((err: HttpErrorResponse) => {
return throwError(err);
}));
}
}
корневой компонент, как показано ниже
import {
Component,
OnInit
} from '@angular/core';
import { CoreApiService } from './core/services/core-api.service';
import { RootDto } from 'src/app/model/root.dto.model';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
constructor(private apiService: CoreApiService) {
}
ngOnInit() {
this.apiService.getRootObject().subscribe((data: RootDto) => {
// todo: do something here
this.apiService.onDataReceived.emit(data);
},
(err: HttpErrorResponse) => {
if (err.status === 401 || err.status === 403) {
// not authorized
}else {
// todo: error happened!
}
}
);
}
}
дочерние компоненты, как показано ниже
import {
Component,
OnInit,
NgZone
} from '@angular/core';
import { CoreApiService } from '../core/services/core-api.service';
import { RootDto } from 'src/app/model/root.dto.model';
import { ChildDto } from '../model/child.dto.model';
@Component({
selector: 'app-first-child',
templateUrl: './firstChild.component.html',
styleUrls: ['./firstChild.component.css']
})
export class FirstChildComponent implements OnInit {
dto: ChildDto;
isLoaded = false;
constructor(private apiService: CoreApiService, private zone: NgZone) {
this.apiService.onDataReceived.subscribe((rootDto: RootDto) => {
this.zone.run(() => {
this.dto = Utils.ObjectFactory.Create(rootDto.firstChildDto); // to make sure that we will have a new reference (so that change detction will be triggered) i use object instantiation
// NOTICE:
// for arrays don't simply assign or push new item to the array, because the reference is not changed the change detection is not triggered
// if the array size is small before assigning new value, you can simply empty (myArray = [];) the array otherwise don't do that
this.isLoaded = true;
});
});
}
ngOnInit() {
}
// the rest of logic
}
вы можете сделать то же самое для всех других компонентов, и даже вы можете создавать больше событий в службе общего доступа и запускать их по своему желанию