![](/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.