在AfterViewInit中更新布尔值会导致“检查后表达式已更改". [英] Updating boolean in AfterViewInit causes "Expression has changed after it was checked"

查看:77
本文介绍了在AfterViewInit中更新布尔值会导致“检查后表达式已更改".的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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:

  • 调用子组件上的OnInitngDoCheck(仅在第一次检查时调用OnInit)
  • 如果当前视图组件实例上的属性已更改,则为当前App视图更新DOM插值和绑定.
  • 调用子OverlayMessage子组件的ngAfterViewInitngAfterViewChecked
  • 为当前App组件调用ngAfterViewInitngAfterViewChecked
  • calls OnInit and ngDoCheck 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 and ngAfterViewChecked for the child OverlayMessage component
  • calls ngAfterViewInit and ngAfterViewChecked for the current App 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆