在AfterViewInit中更新布尔值会导致“检查后表达式已更改”

Dan*_*ima 5 angular2-changedetection angular

我有一个简单的警报组件,该组件正在视图中动态创建。由于它是动态创建的,因此我设置了一个选项,在初始化警报后自动显示该警报。

尽管它可以正常工作,但我想了解为什么在这种特殊情况下为什么必须手动触发更改检测。

码:

export class OverlayMessageComponent implements AfterViewInit {
    ...

    ngAfterViewInit() {
        if(this.autoShow) {
            this.show();
        }
        this.changeDetector.detectChanges();
    }

    ...
}
Run Code Online (Sandbox Code Playgroud)

完整样本: https : //plnkr.co/edit/8NvfhDvLVBd71I7DR0kW

我遇到this.changeDetector.detectChanges();以下错误时必须添加:

例外:检查表达式后,表达式已更改。

我的印象是使用AfterViewInit有助于避免该问题,但我认为我认为这是错误的。有没有一种方法可以更好地结构化代码以避免这种错误?

我想更好地理解为什么返回此错误。我之前已经看过几次这个错误,而且我知道有人说使用a setTimeout()enableProdMode()确实可以解决问题,但是对我来说,当框架本身通知您存在问题时,这似乎是一种错误的解决方法。

Bee*_*ice 5

我想更好地理解为什么返回此错误

AfterViewInitAfterViewChecked变化检测完成后的生命周期挂钩触发并认为已建成。因此,此时运行的任何代码都不应更新视图,否则您的应用及其视图将不同步。快来看看文档

组成视图后,Angular的单向数据流规则禁止对其进行更新。组成组件的视图后,这两个钩子都会触发。

如果挂钩立即更新组件的数据绑定注释属性,则Angular会引发错误。

结果,您必须手动触发更改检测(这是一项昂贵的操作,因为Angular必须再次遍历整个App),或者必须异步进行更改,以便在下一个更改检测步骤中更新视图。诸如:

if(this.autoShow) { setTimeout(()=>this.show,0)}
Run Code Online (Sandbox Code Playgroud)

或更简单地说,如果您不需要抓住视图中的某个东西的句柄,则可以在中运行代码,也可以ngOnInit()稍后在中运行代码ngAfterContentInit()。由于这些操作是在构成视图之前运行的,因此您可以进行影响视图的更改而不会遇到麻烦。

文件:生命周期挂钩顺序


Max*_*kyi 5

修复

对于您的特定情况,无需触发更改检测或使用异步更新。修复很简单,只需将 移动this.showngOnInit生命周期钩子:

  ngOnInit() {
    if(this.autoShow) {
      this.show();
    }
  }
Run Code Online (Sandbox Code Playgroud)

说明

因为您bringIconToFront在模板绑定中使用了组件属性:

<div class="icon home" [class.add-z-index]="bringIconToFront"></div>
Run Code Online (Sandbox Code Playgroud)

Angular 应该更新App组件的 DOM 。此外,Angular 会为子OverlayMessage组件调用生命周期钩子。DOM UDPATE和生命周期钩在顺序执行如图这里

  • 在子组件上调用OnInitngDoCheckOnInit仅在第一次检查时调用)
  • App如果当前视图组件实例上的属性发生更改,则更新当前视图的DOM 插值和绑定`
  • 调用ngAfterViewInitngAfterViewCheckedOverlayMessage组件
  • 调用ngAfterViewInitngAfterViewChecked当前App组件

您可以看到在onInit为当前组件更新 DOM 绑定之前调用了 。并在ngAfterViewInit之后调用。这就是为什么它在一种情况下有效而在另一种情况下不起作用。

本文将帮助您更好地了解错误 - 您需要了解的有关ExpressionChangedAfterItHasBeenCheckedError错误的所有信息