繁体   English   中英

角查询列表更改事件ExpressionChangedAfterItHaHasBeenCheckedError

[英]Angular QueryList change event ExpressionChangedAfterItHasBeenCheckedError

订阅QueryList时,更改事件,对事件作出反应并更改视图绑定到的属性。 我得到一个ExpressionChangedAfterItHaHasBeenCheckedError,该值类似于旧值。

我做了一个stackblitz 示例,显示了错误。

我可以通过在队列中添加微任务来解决它。 但是我只是想了解正在发生的事情。

谢谢

这是发生了什么事;

在开发方式下,如本文“ 相关更改检测操作”部分所述,发生两个连续的CD周期;

正在运行的Angular应用程序是一棵组件树。 在变更检测期间,Angular对每个组件执行检查,该组件包括按指定顺序执行的以下操作:

  1. 更新所有子组件/指令的绑定属性
  2. 在所有子组件/指令上调用ngOnInit,OnChanges和ngDoCheck生命周期挂钩
  3. 更新当前组件的DOM
  4. 对子组件运行更改检测
  5. 为所有子组件/指令调用ngAfterViewInit生命周期挂钩
  • 单击添加按钮后,单击回调完成后,将开始执行更改检测。 comp有1个元素
  • 在第一个CD周期中; DOM在步骤更新在第3元素comp添加到DOM以及{{ count.length }}被投射到DOM作为0
  • @ViewChildren('comp') test: QueryList<ElementRef> 步骤5 之前更新test: QueryList有1个元素
  • 设置ViewChildren查询时,同时在步骤5之前,同时发出QueryList.changes observable。this.count.push this.count.push(this.test.length)被执行, count.length变为1。
  • ngAfterViewChecked被执行,第一张CD(我们调查的相关部分)结束
  • 第二个CD循环开始。 在此循环中,角度检查当前状态下第一CD循环的先前值。
  • 在此检查期间,它遇到{{ count.length }}投影到DOM的值为0,但现在count.length为1的情况。此时,它将引发异常。

解释更多; {{ count.length }}更改为{{ count }}不会引发错误,因为对象引用没有改变。

同样 {{ count.length }}更改为{{ comps.length }}也不会引发错误,因为在第一个CD周期开始之前comps.length也为1。

我还创建了一个演示,该演示在与我们的调查有关的组件生命周期中打印相关步骤。 您可以看到在第四个CD周期开始之前引发了异常。 (第一个和第二个CD循环发生在单击按钮之前,因此应注意演示第三个和第4个CD循环)。 还应注意QueryList.changes发出值的地方。

https://stackblitz.com/edit/angular-tmcttm

最后,正如您所说,解决此特定问题的方法是通过更改此行将微任务添加到队列中

this.count.push(this.test.length);

进入这个

setTimeout(_ => this.count.push(this.test.length));

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM