【问题标题】:Getting ExpressionChangedAfterItHasBeenCheckedError error I update property of a Component from another Component获取 ExpressionChangedAfterItHasBeenCheckedError 错误我从另一个组件更新组件的属性
【发布时间】:2018-09-13 01:11:31
【问题描述】:

演示可在此处获得 - https://stackblitz.com/edit/angular-a9wcee

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

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

我读到Input 不适用于引导组件,因此我将index.html 中的属性作为“启动上下文”传递给ComponentA

<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 尝试更改@987654343 @(message 属性)如果它确定它必须显示对话框(ComponentB)(通过检查属性)。我认为这与Change Detection 产生了问题,而我Angular 正在抛出ExpressionChangedAfterItHasBeenCheckedError 错误。如何重新设计组件交互

ComponentA的代码sn-ps是

  • 检查我是如何开始的。

     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 {
    
        }
    

    }

更新ComponentBmessage 属性并显示它的逻辑

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');

  }

ComponentBhtml

<div #modal class="modal fade" tabindex="-1" role="dialog" id={{dialogID}}>
  <div class="modal-dialog modal-dialog-centered" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title">CodingJedi</h5>
        <button type="button" class="close" data-dismiss="modal" aria-label="Close" (click)="dialogHide()">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body">
        <p>{{dialogMessage}}</p>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary" data-dismiss="modal" (click)="dialogHide()">Close</button>
      </div>
    </div>
  </div>
</div>

【问题讨论】:

    标签: angular6


    【解决方案1】:

    文章很好地解释了导致错误的原因 - 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

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

    有两种方法可以解决此问题。使用setTimeout 创建下一个任务,该任务将在当前更改检测任务完成后执行,或者在更改DialogBoxComponentdialogMessage 后,使用detectChanges() 再次运行更改检测

    ngAfterViewChecked(){
        setTimeout(()=>this.isSignupProcess());
    
        }
    
        OR
    ngAfterViewChecked(){
        this.isSignupProcess(); 
        this.cd.detectChanges();
        }
    

    【讨论】:

      猜你喜欢
      • 2019-02-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-07-04
      • 2021-07-23
      • 2020-07-01
      • 1970-01-01
      • 2019-03-08
      相关资源
      最近更新 更多