角。使用HostBinding装饰器手动更新属性

时间:2018-06-14 11:52:24

标签: angular

我有一个具有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调用可以防止错误。

1 个答案:

答案 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

相关问题