我有一个具有HostBinded属性的组件,我想从其他组件手动更新。我是这样写的:
private _selected: boolean = false;
@HostBinding('class.selected')
get selected(): boolean {
return this._selected;
}
set selected(value: boolean) {
if (this._selected === value) {
return;
}
this._selected = value;
this.changeDetectorRef.markForCheck();
}
我有两个问题。
第一即可。当我尝试更新ContentChild
的属性时 - 不会应用更改。请参阅此处的示例 - https://stackblitz.com/edit/angular-changes-ignored-contentchildren-hostbinding:
@ContentChildren(ItemComponent) items: QueryList<ItemComponent>;
...
ngAfterViewInit() {
this.updateItems();
this.items.changes.subscribe(() => {
this.updateItems();
});
this.changeDetectorRef.markForCheck();
}
private updateItems() {
this.items.forEach(item => {
item.selected = this.selected === item.value;
});
}
如果我添加
setTimeout(() => {
this.changeDetectorRef.markForCheck();
});
然后UI会更新,但我不明白为什么需要它。
第二即可。当我尝试更新ViewChild
的属性时 - 抛出ExpressionChanged错误。示例 - https://stackblitz.com/edit/angular-expression-has-changed-viewchild-hostbinding。
@ViewChild(ItemComponent) item: ItemComponent;
...
ngAfterViewInit() {
this.item.selected = true;
this.changeDetectorRef.markForCheck();
}
又是为什么?通常markForCheck
调用可以防止错误。
答案 0 :(得分:1)
关于第二。由于the nature of ngAfterViewInit而引发错误 - 它在更改检测周期后运行,此处的任何更改都将触发错误(仅在开发模式下)。但是有一些有趣的时刻。
正如我使用OnPush
策略markForCheck
实际触发了错误,如果删除了对它的所有调用,则不会显示任何错误,也不会应用任何更改。
另一方面,markForCheck
显然在它已经发挥作用时不会触发新一轮的变更检测。
因此解决方案是在更改检测之前运行ngOnInit
挂钩时应用更改,并且ViewChild
在那里可用。或者调用detectChanges
markForChek
的插入内容,因为它会触发新的更改检测周期。
https://stackblitz.com/edit/angular-expression-has-changed-viewchild
首先一个。这种情况与以前不同 - 现在有三个组件:App,List和Item。项目和列表在App模板中创建,然后项目在List中投影。
首先,列表detectChanges
内的ngAfterViewInit
不会更新项目,可能是因为项目不是直接子项或列表的父项。此外,如果不在应用markForCheck
中调用markForCheck
,则调用ngAfterViewInit
不会触发错误(如第二情况)。
正确的方法是在List ngAfterContentInit
中应用更改。此挂钩在更改检测之前运行,所有内容都将正确呈现到dom中。
https://stackblitz.com/edit/angular-changes-ignored-contentchildren