代码之家  ›  专栏  ›  技术社区  ›  Sergey Sokolov

有角的使用hostbinding decorator手动更新属性

  •  0
  • Sergey Sokolov  · 技术社区  · 7 年前

    我有一个具有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();
    });
    

    然后用户界面将被更新,但我不明白为什么它需要。

    第二 . 当我尝试更新的属性 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 回复  |  直到 7 年前
        1
  •  1
  •   Sergey Sokolov    7 年前

    关于 第二 . 引发错误的原因是 the nature of ngAfterViewInit -它在更改检测周期之后运行,此处的任何更改都将触发错误(仅在开发模式下)。但很少有有趣的时刻。

    正如我所使用的 OnPush 策略 markForCheck 实际上触发了错误,如果删除了对它的所有调用,则不会显示任何错误,也不会应用任何更改。

    另一件事是 马尔科夫检查 显然,当新一轮的变化检测已经开始运行时,它不会触发。

    所以解决方法要么是在 ngOnInit 在检测到变化之前钩住 ViewChild 那里有空。或打电话 detectChanges 内幕 markForChek 因为它触发了新的变更检测周期。

    https://stackblitz.com/edit/angular-expression-has-changed-viewchild

    弗斯特 一个。这个案例与之前不同-现在有三个组件:app、list和item。项目和列表在应用程序的模板中创建,然后项目在列表中投影。

    首先 检测更改 内部列表 ngAfterViewInit 不会更新项,可能是因为项不是列表的直接子项或父项。此外,打电话 马尔科夫检查 不会触发错误(如 第二 案例)不打电话 马尔科夫检查 应用程序的 ngafterviewinit .

    正确的方法是在列表中应用更改 ngAfterContentInit 。此钩子在更改检测之前运行,所有内容都将正确呈现到dom中。

    https://stackblitz.com/edit/angular-changes-ignored-contentchildren