"表达在检查后发生了变化"当子组件在ngOnInit

时间:2017-02-12 16:40:59

标签: angular

我有一个父组件,它显示验证错误列表,并使用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中包装逻辑相同,但这样至少我们不必将代码包装在超出我们可能发出值的任何地方。

2 个答案:

答案 0 :(得分:3)

Angular不喜欢更改检测本身导致更改并且更改检测调用ngOnInit

在devMode中,更改检测会在每次常规更改检测运行后执行其他更改检测,以检查模型是否稳定。 如果在更改检测期间模型已更改,则会抛出此错误。

您可以使用

延迟更改,直到更改检测完成
  ngOnInit() {
    setTimeout(() => {
      this.output.emit({value: true});
    }
  }

Plunker example

更新(请参阅下面的Ghetolay评论)

  更改检测不会调用

ngOnInit,您可以在其中进行绑定更改。你不能做的是对孩子的父母ngOnInit做出改变,因为这会打破单向数据流。

另见https://github.com/angular/angular/issues/10131#issuecomment-233369491

答案 1 :(得分:0)

您无法更改ngOnInit中的任何内容。 Angular 2团队拒绝将此视为错误(#10131),所以是的,您必须以不洁方式执行此操作:setTimeout(..., 0)Promise.resolve().then(...)