获取ExpressionChangedAfterItHaHasBeenCheckedError错误我从另一个组件更新了一个组件的属性

时间:2018-09-09 16:19:41

标签: angular6

此处提供了演示-https://stackblitz.com/edit/angular-a9wcee

请打开控制台窗口以查看错误。

说明 我有一个Bootstrap组件ComponentA,该组件应根据应用程序的启动过程以两种不同的方式启动。假设如果使用URL home.com启动应用程序,则ComponentA在启动时不应显示弹出对话框,但是如果使用home.com;signup启动应用程序,则应显示弹出窗口。 / p>

我已经了解到Input对引导程序组件无效,因此我将ComponentA的属性作为“启动上下文”传递给index.html

<comp-a someAttr="someValue"></comp-a> <!--depending on whether someAttr is empty ("") or not, the pop should not be shown or shown respectively -->

ComponentA在其模板中使用DialogComponent如下

<comp-dialog [message]=""></comp-dialog> <!-- I want the input to ComponentB to be empty to begin with -->

ComponentB是一个Bootstrap css对话框,并显示一条Input消息,该消息将在对话框变为可见时显示。棘手的是,ComponentBComponentA的模板中,因此Angular在ComponentA启动时但在ComponentA启动完成之前对其进行了初始化,如果ComponentA确定必须显示对话框(ComponentB),则尝试更改messageComponentB属性)(通过检查属性)。我认为这正在为Change Detection造成问题,并且我Angular抛出ExpressionChangedAfterItHasBeenCheckedError错误。如何重新设计组件交互

ComponentA的代码段是

  • 检查我是如何开始的。

     ngAfterViewChecked(){
        this.signup = this.el.nativeElement.getAttribute('signup'); //get the attribute
        this.isSignupProcess();//check if ComponentB needs to be shown and update its message property
      }
    
      isSignupProcess(){
        console.log("sign up is "+this.signup)
        if(this.signup!==""){ //show ComponentB
          if(this.signup === "success") {
            this.showDialog("Signup was successful",new DialogContext("","")) //set message property of ComponentB
          }else if(this.signup === "error") {
            this.showDialog("Error: Signup wasn't successful",new DialogContext("",""))
          } else {
            this.showDialog("Unrecognised message: "+this.signup,new DialogContext("",""))
          }
          this.signup = ""; //no need to show ComponentB
    
        } else {
    
        }
    

    }

更新message的{​​{1}}属性并将其显示为逻辑的逻辑

ComponentB

showDialog(message:string,context:DialogContext) { this.dialogComponent.dialogShow(message,context); } 只需调用ComponentB的模态函数

Bootstrap

dialogShow(message:string, context:DialogContext){ this.dialogContext = context; this.dialogMessage = message; console.log("dialog got context ",this.dialogContext); $(this.dialogRef.nativeElement).modal('show'); } 中的html

ComponentB

1 个答案:

答案 0 :(得分:0)

本文很好地说明了导致错误的原因-https://blog.angularindepth.com/everything-you-need-to-know-about-the-expressionchangedafterithasbeencheckederror-error-e3fd9ce7dbb4

从链接中引用,Angular中的更改检测通过以下步骤     1)更新所有子组件/指令的绑定属性,即和插值{{}}     2)在所有子组件/指令上调用ngOnInit,OnChanges和ngDoCheck生命周期挂钩     3)更新当前组件的DOM     4)对子组件运行更改检测     5)为所有子组件/指令调用ngAfterViewInit生命周期挂钩

每次操作后,Angular都会记住用于执行操作的值。 它们存储在组件视图的oldValues属性中。

对所有组件进行检查之后,Angular会将当前值与上一个摘要周期中记住的值进行比较:       1)检查传递给子组件的值是否与现在用于更新这些组件的属性的值相同       2)检查用于更新DOM元素的值是否与现在用于更新这些元素的值相同       3)对所有子组件执行相同的检查

此后,Angular将运行一个验证循环,以检查用于创建子组件和DOM中的值是否相同,否则更改检测将在一个循环后保持稳定,并可能在无限循环中结束。如果Angular发现在当前更改检测周期完成之前用于创建子组件或DOM的值已更改,则它将抛出ExpressionChangedAfterItHasBeenCheckedError

在我的代码中,使用初始值dialogMessagedialogContext创建DialogComponent。现在,根据应用程序的启动方式,我想更新消息并显示对话框。如果我只更新dialogMessage,则Angular将给出错误ExpressionChangedAfterItHasBeenCheckedError,因为dialogMessage的值在当前更改检测周期结束之前已更改。

有两种方法可以解决此问题。使用setTimeout创建下一个任务,该任务将在当前更改检测任务完成后执行,或者在更改dialogMessage的{​​{1}}之后,使用DialogBoxComponent再次运行更改检测

detectChanges()