#angular #typescript #api
Вопрос:
В родительском компоненте я получаю данные из API, допустим, это объект с некоторыми свойствами в нем. В полученном объекте «структура» — это свойство, которое я хочу отправить дочернему компоненту, и с помощью этого свойства я добавляю класс к использованию Renderer2, проверяя значение «структуры».
когда я пытаюсь добавить класс к элементу div , он говорит , что div не определен
Родительский компонент :
@Component({
selector: 'dashboard',
templateUrl: './dashboard.component.html',
styleUrls: ['./dashboard.component.scss']
})
dashboardModel;
loadReport(){
this.ApiService('The-Api-Url',300).subscribe((result)=>{
this.dashboardModel = result.dashboardModel;
})
}
///Number 300 is just to show you , it's not important !
Родительский HTML-код :
<dashboard-view
[dashboardModel]="dashboardModel"
></dashboard-view>
Дочерний компонент :
@Component({
selector: 'dashboard-view',
template: `
<div
#widgetContainer
class="container"
id="widget-view">
</div>
`,
styleUrls: ['./dashboard-view.component.scss']
})
export class DashboardViewComponent implements OnInit {
constructor(private renderer : Renderer2){}
@Input() dashboardModel
@ViewChild ('widgetContainer') widgetContainer :ElementRef
creatStructure(){
this.renderer.addClass(this.widgetContainer.nativeElement , 'container-edit-mode')
}
ngOninit(){
this.creatStructure()
}
}
Я пытался вызвать creatStructure()
метод в OnInit и AfterViewInit и даже в AfterContentInit, но он всегда говорит, что WidgetContainer не определен.
Пример кода StackBlitz: https://stackblitz.com/edit/angular-ivy-bdpbwx?file=src/app/child/child.component.ts
Комментарии:
1. Используйте ngAfterViewInit вместо ngOnInit
2. @MikeOne Я пытался, но вызов api происходит после установки значения dashboardModel
3. Ваша демонстрационная версия StackBlitz не запускается — в ряде файлов отсутствует импорт и ошибки, не связанные с вашим вопросом:-)
Ответ №1:
Несколько вариантов, которые я мог бы предложить без этого рабочего стека.
- Не используйте средство визуализации для установки класса. Установите его в шаблоне с помощью getter; тогда вы не беспокоитесь о просмотре дочерних объектов и порядке инициализации.
Шаблон:
<div
#widgetContainer
class="container"
[class.container-edit-mode]="isEditMode"
id="widget-view">
</div>
Компонент:
public get isEditMode(): boolean {
return this.dashboardModel
amp;amp; this.dashboardModel.structure
amp;amp; this.dashboardModel.structure === '12';
}
Это защищает от того, что модель панели мониторинга еще не установлена (что является вашей текущей проблемой, поскольку вызов API происходит после инициализации).
- Выводите компонент на экран только после получения данных. Спрячьте свой компонент за an
*ngIf
, чтобы он создавался только после того, как у вас будут данные, тогда вы гарантированно будетеthis.dashboardModel
заполненыngOnInit
вовремя.
Родительский шаблон:
<ng-container *ngIf="dashboardModel">
<dashboard-view
[dashboardModel]="dashboardModel">
</dashboard-view>
</ng-container>
Примечание: вам все равно нужно разобраться с порядком инициализации дочернего элемента представления, если вы придерживаетесь прямого использования средства визуализации для настройки класса…
- Исправьте порядок инициализаций. Как уже упоминалось, если вы собираетесь что-то делать с вашим представлением с помощью средства визуализации, делайте это в / после
ngAfterViewInit
этапа жизненного цикла. До этого ваш шаблон не существовал, поэтому все ваши дочерние объекты view останутся неопределенными.
Вы можете переключить свой ввод на a set
, чтобы вы могли вносить соответствующие изменения, когда вы получаете эти данные API, и оставить свой компонент неинициализированным до тех пор.
Компонент:
@Input() public set dashboardModel(value: DashboardModel) {
this._dashboardModel = value;
this.initModel();
}
private initModel(): void {
if (!this.widgetContainer) console.error(`Hopefully this shouldn't happen`);
if (this._dashboardModel.structure === '12')
this.renderer.addClass(this.widgetContainer.nativeElement , 'container-edit-mode');
}