此处提供了演示-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
消息,该消息将在对话框变为可见时显示。棘手的是,ComponentB
在ComponentA
的模板中,因此Angular在ComponentA
启动时但在ComponentA
启动完成之前对其进行了初始化,如果ComponentA
确定必须显示对话框(ComponentB
),则尝试更改message
(ComponentB
属性)(通过检查属性)。我认为这正在为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
答案 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
在我的代码中,使用初始值dialogMessage
和dialogContext
创建DialogComponent。现在,根据应用程序的启动方式,我想更新消息并显示对话框。如果我只更新dialogMessage
,则Angular将给出错误ExpressionChangedAfterItHasBeenCheckedError
,因为dialogMessage
的值在当前更改检测周期结束之前已更改。
有两种方法可以解决此问题。使用setTimeout
创建下一个任务,该任务将在当前更改检测任务完成后执行,或者在更改dialogMessage
的{{1}}之后,使用DialogBoxComponent
再次运行更改检测>
detectChanges()