我有一个父组件,它显示验证错误列表,并使用ngFor
呈现子组件列表。每个子组件在ngOnInit
期间执行其验证,并将结果输出到父组件。父组件侦听此输出并更新验证错误列表,其结果将引发错误:
Expression has changed after it was checked
现在,我理解为什么会抛出这个错误 - 在更改检测周期的开始,验证错误处于一个状态,最后它处于另一个状态,这是不允许的。
我不明白的是如何解决这个问题。父组件必须在页面顶部显示错误列表,每个子组件都会将其验证结果添加到此列表中。如果这违反了单向数据流,请告诉我如何以干净的方式解决这个问题(即,不将验证包装在setTimeout
中,而不是从不可变列表更改为可变列表,并且在验证后没有明确地再次调用变化检测器。
Plunker再现问题:https://plnkr.co/edit/q52A1DraNOnxZa0qGFDo?p=preview
修改
我已经解决了#34;通过使用EventEmitter
标志构建isAsync
来解决问题:
new EventEmitter(true)
这意味着将以异步方式发出值,因此将在 next 更改检测周期中拾取发出的值。我想结果与在setTimeout
中包装逻辑相同,但这样至少我们不必将代码包装在超出我们可能发出值的任何地方。
答案 0 :(得分:3)
Angular不喜欢更改检测本身导致更改并且更改检测调用ngOnInit
。
在devMode中,更改检测会在每次常规更改检测运行后执行其他更改检测,以检查模型是否稳定。 如果在更改检测期间模型已更改,则会抛出此错误。
您可以使用
延迟更改,直到更改检测完成 ngOnInit() {
setTimeout(() => {
this.output.emit({value: true});
}
}
更新(请参阅下面的Ghetolay评论)
更改检测不会调用
ngOnInit
,您可以在其中进行绑定更改。你不能做的是对孩子的父母ngOnInit
做出改变,因为这会打破单向数据流。
另见https://github.com/angular/angular/issues/10131#issuecomment-233369491
答案 1 :(得分:0)
您无法更改ngOnInit
中的任何内容。 Angular 2团队拒绝将此视为错误(#10131),所以是的,您必须以不洁方式执行此操作:setTimeout(..., 0)
或Promise.resolve().then(...)
。