在AfterViewInit中更新布尔值会导致“检查后表达式已更改". [英] Updating boolean in AfterViewInit causes "Expression has changed after it was checked"
问题描述
我有一个简单的警报组件,该组件正在视图中动态创建.由于它是动态创建的,因此我设置了一个选项,在初始化警报后自动显示该警报.
I have a simple alert component which I'm creating dynamically in the view. Since it's created dynamically I've set an option to automatically display the alert after it has been initialised.
尽管它正在运行,但我想了解为什么在这种特殊情况下为什么必须手动触发更改检测.
Although it's working I'd like to understand why I have to manually trigger the change detection in this particular case.
代码:
export class OverlayMessageComponent implements AfterViewInit {
...
ngAfterViewInit() {
if(this.autoShow) {
this.show();
}
this.changeDetector.detectChanges();
}
...
}
完整示例:: https://plnkr.co/edit/8NvfhDvLVBd71I7DR0kW
在出现以下错误时,我必须添加this.changeDetector.detectChanges();
:
I had to add this.changeDetector.detectChanges();
as I was getting the following error:
例外:检查后表达式已更改.
EXCEPTION: Expression has changed after it was checked.
给我的印象是,使用AfterViewInit
可以避免该问题,但是我认为我认为这是错误的.有没有一种方法可以更好地结构化代码以避免这种错误?
I was under the impression that using AfterViewInit
helps avoiding the issue, but I think I'm assuming wrong. Is there a way to structure the code better to avoid this error?
我想更好地理解为什么返回此错误.我之前已经看过几次这个错误,而且我知道有人说使用setTimeout()
或enableProdMode()
确实可以解决问题,但是对我来说,当框架本身通知您有一个问题.
I'd like to understand better why this error is returned. I've seen this error a few times before, and I know that some say that with a setTimeout()
or enableProdMode()
does solve the issue, but to me it seems a hacky workaround when the framework itself is notifying you that there's a problem.
推荐答案
修复
对于您的特定情况,无需触发更改检测或使用异步更新.修复很简单,只需将this.show
移至ngOnInit
生命周期挂钩:
The fix
For your particular case there's no need to trigger change detection or use async update. The fix is simple, just move the this.show
to the ngOnInit
lifecycle hook:
ngOnInit() {
if(this.autoShow) {
this.show();
}
}
解释
因为您在模板绑定中使用了bringIconToFront
组件属性:
<div class="icon home" [class.add-z-index]="bringIconToFront"></div>
Angular应该更新App
组件的DOM.另外,Angular调用子OverlayMessage
组件的生命周期挂钩. DOM udpate和生命周期挂钩按如下顺序执行:
Angular should update the DOM of the App
component. Also, Angular calls lifecycle hooks for the child OverlayMessage
component. DOM udpate and lifecycle hooks are performed in order as shown here:
- 调用子组件上的
OnInit
和ngDoCheck
(仅在第一次检查时调用OnInit
)
- 如果当前视图组件实例上的属性已更改,则为当前
App
视图更新DOM插值和绑定.
- 调用子
OverlayMessage
子组件的ngAfterViewInit
和ngAfterViewChecked
- 为当前
App
组件调用ngAfterViewInit
和ngAfterViewChecked
- calls
OnInit
andngDoCheck
on a child component (OnInit
is called only during first check) - updates DOM interpolations and bindings for the current
App
view if properties on current view component instance changed` - calls
ngAfterViewInit
andngAfterViewChecked
for the childOverlayMessage
component - calls
ngAfterViewInit
andngAfterViewChecked
for the currentApp
component
您可以看到在为当前组件更新DOM绑定之前,已调用onInit
.然后ngAfterViewInit
被调用.这就是为什么它在一种情况下有效而在另一种情况下无效的原因.
You can see that the onInit
is called before the DOM bindings are updated for the current component. And the ngAfterViewInit
is called after. That is why it works in one case and doesn't work in the other.
本文将帮助您更好地理解错误-
所有您需要了解的ExpressionChangedAfterItHasBeenCheckedError
错误信息.
This article will help you understand the error better -
Everything you need to know about the ExpressionChangedAfterItHasBeenCheckedError
error.
这篇关于在AfterViewInit中更新布尔值会导致“检查后表达式已更改".的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!