![](/img/trans.png)
[英]Angular change detection error: ExpressionChangedAfterItHasBeenCheckedError
[英]Angular QueryList change event ExpressionChangedAfterItHasBeenCheckedError
订阅QueryList时,更改事件,对事件作出反应并更改视图绑定到的属性。 我得到一个ExpressionChangedAfterItHaHasBeenCheckedError,该值类似于旧值。
我做了一个stackblitz 示例,显示了错误。
我可以通过在队列中添加微任务来解决它。 但是我只是想了解正在发生的事情。
谢谢
这是发生了什么事;
在开发方式下,如本文“ 相关更改检测操作”部分所述,发生两个连续的CD周期;
正在运行的Angular应用程序是一棵组件树。 在变更检测期间,Angular对每个组件执行检查,该组件包括按指定顺序执行的以下操作:
- 更新所有子组件/指令的绑定属性
- 在所有子组件/指令上调用ngOnInit,OnChanges和ngDoCheck生命周期挂钩
- 更新当前组件的DOM
- 对子组件运行更改检测
- 为所有子组件/指令调用ngAfterViewInit生命周期挂钩
comp
有1个元素 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(我们调查的相关部分)结束 {{ 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.