获取ExpressionChangedAfterItHaHasBeenCheckedError错误我从另一个组件更新了一个组件的属性 [英] Getting ExpressionChangedAfterItHasBeenCheckedError error I update property of a Component from another Component
问题描述
可在此处获得该演示- https://stackblitz.com/edit/angular-a9wcee
The demo is available here - https://stackblitz.com/edit/angular-a9wcee
请打开控制台窗口以查看错误.
Please open the console window to see the error.
说明
我有一个Bootstrap
组件ComponentA
,应根据应用程序的启动过程以两种不同的方式启动.假设如果使用url home.com
启动应用程序,则ComponentA
不应在启动时显示弹出对话框,但是如果使用home.com;signup
启动应用程序,则应用程序应该显示弹出窗口.
Description
I have a Bootstrap
component ComponentA
which should start up in two different ways depending on the application's startup process. Say if the application is started using url home.com
then ComponentA
should not show a pop up dialog on startup but if the application is started using home.com;signup
then the application should show a pop up.
我已经了解到Input
不适用于引导程序组件,因此我将属性从我的index.html
传递给ComponentA
作为启动上下文".
I have read that Input
doesn't work for bootstrap components so I am passing an attribute to ComponentA
from my index.html
as a "startup context".
<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
消息,该消息将在对话框可见时显示.棘手的是,ComponentB
在ComponentA
的模板中,因此Angular在ComponentA
的启动过程中对其进行了初始化,但在ComponentA
的启动完成之前,ComponentA
尝试更改message
属性)(如果确定必须显示对话框(ComponentB
))(通过检查属性).我认为这会导致Change Detection
出现问题,而我Angular
会抛出ExpressionChangedAfterItHasBeenCheckedError
错误.我该如何重新设计组件交互
ComponentB
is a Bootstrap
css
dialog box and takes an Input
message which it shows when the dialog becomes visible. The tricky bit is that ComponentB
is in ComponentA
's template and thus Angular initialised it as part of ComponentA
's start up but before ComponentA
's start up finished, ComponentA
tries to change ComponentB
(the message
property) if it determines that it has to show the dialog box (ComponentB
) (by checking the attribute). I think this is creating issues with Change Detection
and I am Angular
is throwing ExpressionChangedAfterItHasBeenCheckedError
error. How could I redesign the component interaction
ComponentA
的代码段为
-
检查我是如何开始的.
Check how I was started.
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 {
}
}
更新ComponentB
的message
属性并显示它的逻辑
the logic to update message
property of ComponentB
and show it is
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');
}
ComponentB
的html
是
<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">×</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>
推荐答案
The article explains well what causes the error - 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生命周期挂钩
Quoting from the link, Change detection in Angular goes through the following steps 1) update bound properties for all child components/directives i.e. and interpolation values {{}} 2) call ngOnInit, OnChanges and ngDoCheck lifecycle hooks on all child components/directives 3) update DOM for the current component 4) run change detection for a child component 5) call ngAfterViewInit lifecycle hook for all child components/directives
每次操作后,Angular都会记住用于执行操作的值. 它们存储在组件视图的oldValues属性中.
After each operation Angular remembers what values it used to perform an operation. They are stored in the oldValues property of the component view.
检查完所有组件后,Angular会将当前值与上一个摘要循环中记住的值进行比较: 1)检查传递给子组件的值是否与现在用于更新这些组件的属性的值相同 2)检查用于更新DOM元素的值是否与现在用于更新这些元素的值相同 3)对所有子组件执行相同的检查
After the checks have been done for all components, Angular compares the current values with the ones it remembers from the previous digest cycle: 1) check that values passed down to the child components are the same as the values that would be used to update properties of these components now 2) check that values used to update the DOM elements are the same as the values that would be used to update these elements now 3) perform the same checks for all child components
此后,Angular运行一个验证周期,以检查用于创建子组件和DOM中的值是否相同,否则更改检测将在一个周期后不再稳定,并可能以无限循环结束.如果Angular发现在当前更改检测周期结束之前用于创建子组件或DOM的值已更改,则它将抛出ExpressionChangedAfterItHasBeenCheckedError
After this, Angular runs a verification cycle to check that the values used to create Child Components and in DOM are still the same otherwise the change detection will not stabalise after one cycle and could end in infinite loop. If Angular finds that the value used to create a child component or used on DOM has changed before the current change detection cycle has finished then it will throw ExpressionChangedAfterItHasBeenCheckedError
在我的代码中,使用初始值dialogMessage
和dialogContext
创建DialogComponent.现在,根据应用程序的启动方式,我想更新消息并显示对话框.如果我只更新dialogMessage
,则Angular将给出错误ExpressionChangedAfterItHasBeenCheckedError
,因为dialogMessage
的值在当前更改检测周期结束之前已更改.
In my code, DialogComponent is created with initial values of dialogMessage
and dialogContext
. Now, depending on how the app got started, I want to update the message and show the dialog box. If I just update the dialogMessage
, Angular will give error ExpressionChangedAfterItHasBeenCheckedError
because the value of dialogMessage
had changed before the current change detection cycle finished.
有两种方法可以解决此问题.使用setTimeout
创建下一个将在当前更改检测任务完成后执行的任务,或者在更改DialogBoxComponent
的dialogMessage
之后,使用detectChanges()
There are two ways to fix the issue. Use setTimeout
to create the next task which will be executed once the current change detection task finishes OR after changing the dialogMessage
of DialogBoxComponent
, run change detection again using detectChanges()
ngAfterViewChecked(){
setTimeout(()=>this.isSignupProcess());
}
OR
ngAfterViewChecked(){
this.isSignupProcess();
this.cd.detectChanges();
}
这篇关于获取ExpressionChangedAfterItHaHasBeenCheckedError错误我从另一个组件更新了一个组件的属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!