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()确实可以解决问题,但是对我来说,当框架本身通知您存在问题时,这似乎是一种错误的解决方法。
我想更好地理解为什么返回此错误
该AfterViewInit和AfterViewChecked变化检测完成后的生命周期挂钩触发并认为已建成。因此,此时运行的任何代码都不应更新视图,否则您的应用及其视图将不同步。快来看看文档
组成视图后,Angular的单向数据流规则禁止对其进行更新。组成组件的视图后,这两个钩子都会触发。
如果挂钩立即更新组件的数据绑定注释属性,则Angular会引发错误。
结果,您必须手动触发更改检测(这是一项昂贵的操作,因为Angular必须再次遍历整个App),或者必须异步进行更改,以便在下一个更改检测步骤中更新视图。诸如:
if(this.autoShow) { setTimeout(()=>this.show,0)}
Run Code Online (Sandbox Code Playgroud)
或更简单地说,如果您不需要抓住视图中的某个东西的句柄,则可以在中运行代码,也可以ngOnInit()稍后在中运行代码ngAfterContentInit()。由于这些操作是在构成视图之前运行的,因此您可以进行影响视图的更改而不会遇到麻烦。
文件:生命周期挂钩顺序
对于您的特定情况,无需触发更改检测或使用异步更新。修复很简单,只需将 移动this.show到ngOnInit生命周期钩子:
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和生命周期钩在顺序执行如图这里:
OnInit和ngDoCheck(OnInit仅在第一次检查时调用)App如果当前视图组件实例上的属性发生更改,则更新当前视图的DOM 插值和绑定`ngAfterViewInit和ngAfterViewChecked子OverlayMessage组件ngAfterViewInit和ngAfterViewChecked当前App组件您可以看到在onInit为当前组件更新 DOM 绑定之前调用了 。并在ngAfterViewInit之后调用。这就是为什么它在一种情况下有效而在另一种情况下不起作用。
本文将帮助您更好地了解错误 -
您需要了解的有关ExpressionChangedAfterItHasBeenCheckedError错误的所有信息。