この記事の概要
Angularで時々目にするExpressionChangedAfterItHasBeenCheckedErrorですが、
原因は今回記事でとりあげるものの他にも様々ありますが、
私のチームでよくやってしまいがちな
このエラー発生させるコードの記述の仕方と解決策のメモを残します。
Chromeのコンソールに出てるエラーログ
HogeComponent.html:1037 ERROR Error: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'ngIf: false'. Current value: 'ngIf: true'.
at viewDebugError (core.js:7602)
at expressionChangedAfterItHasBeenCheckedError (core.js:7590)
at checkBindingNoChanges (core.js:7692)
at checkNoChangesNodeInline (core.js:10553)
at checkNoChangesNode (core.js:10542)
at debugCheckNoChangesNode (core.js:11145)
at debugCheckDirectivesFn (core.js:11073)
at Object.eval [as updateDirectives] (HogeComponent.html:1037)
at Object.debugUpdateDirectives [as updateDirectives] (core.js:11062)
at checkNoChangesView (core.js:10441)
どうやらngIfの判定がfalseだったのにtrueに変わっているぞと怒られているようです。
エラーとなっているコード
<ng-container *ngIf="fuga.invalid && submitted">
<span>foo</span>
</ng-container>
原因
この*ngIfの中のfuga.invalid と submittedの評価の結果が返ってくるのはそれぞれ時間差がありました。
例えば最初にsubmitがtrue、fuga.invalidがfalseと判定されたので、
Angularは変更を感知してng-container内の要素を表示をしないようにしたところ、
その直後すぐにfuga.invalidの判定がtrueで返ってきたので
ng-container内の要素を表示する判定が変わってしまいました。
修正
<ng-container *ngIf="submitted">
<ng-container *ngIf="fuga.invalid">
<span>foo</span>
</ng-container>
</ng-container>
これで
外側のngIfの条件判定でsubmitがtrueになった
↓
Angularは変更を感知して外側のng-container内部を表示する
↓
次に内側のngIfの条件判定でfuga.invalidがtrueになった
↓
Angularは変更を感知して内側のng-container内部を表示する
という順序で無理なく要素を表示することができます。