MeWrite Docs

Angular: ExpressionChangedAfterItHasBeenCheckedError

Angularの変更検知後にデータが変更された場合のエラー

概要

Angularの変更検知サイクル中にバインドされたデータが変更された場合に発生するエラーです。開発モードでのみ表示されます。

エラーメッセージ

ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked.
Previous value: 'ngIf: false'. Current value: 'ngIf: true'.

原因

  1. ngAfterViewInitでデータ変更: ビュー初期化後にバインドされた値を変更
  2. 子コンポーネントからの値変更: 親のプロパティを子が変更
  3. 非同期処理のタイミング: 変更検知中に非同期でデータが更新

解決策

1. setTimeout で次の変更検知サイクルに延期

1
2
3
4
5
ngAfterViewInit() {
  setTimeout(() => {
    this.isLoaded = true;
  });
}

2. ChangeDetectorRef を使用

1
2
3
4
5
6
7
8
import { ChangeDetectorRef } from '@angular/core';

constructor(private cdr: ChangeDetectorRef) {}

ngAfterViewInit() {
  this.isLoaded = true;
  this.cdr.detectChanges();
}

3. ngAfterContentChecked を使用

1
2
3
ngAfterContentChecked() {
  this.cdr.detectChanges();
}

4. OnPush 変更検知戦略

1
2
3
4
5
6
7
8
@Component({
  selector: 'app-example',
  templateUrl: './example.component.html',
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class ExampleComponent {
  // ...
}

5. 非同期パイプを使用

1
2
// コンポーネント
data$ = this.dataService.getData();
1
2
3
4
<!-- テンプレート -->
<div *ngIf="data$ | async as data">
  {{ data.name }}
</div>

6. BehaviorSubject を使用

1
2
3
4
5
6
private isLoadedSubject = new BehaviorSubject<boolean>(false);
isLoaded$ = this.isLoadedSubject.asObservable();

ngAfterViewInit() {
  this.isLoadedSubject.next(true);
}

よくある間違い

  • ngOnInitで非同期処理の結果を同期的に使用
  • @ViewChildの値をngAfterViewInitで変更
  • 親コンポーネントの値を@Outputで即座に変更

Angular の他のエラー

最終更新: 2025-12-09