親コンポーネント内=>
ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: ''. Current value: '[object Object]'.
at viewDebugError (vendor.bundle.js:8962)
at expressionChangedAfterItHasBeenCheckedError (vendor.bundle.js:8940)
親コンポーネント HTML
<div>
<app-child-widget [allItems]="allItems" (notify)="eventCalled($event)"></app-child-widget>
<div>
親コンポーネント
export class ParentComponent implements OnInit {
returnedItems: Array<any> = [];
allItems: Array<any> = [];
constructor(
) { }
ngOnInit() {
this.allItems = // load from server...
}
eventCalled(items: Array<any>): void {
this.returnedItems = items;
}
}
子コンポーネント
@Component({
selector: 'app-child-widget',
templateUrl: 'child.component.html',
styleUrls: ['./child.component.css']
})
export class ChildComponent implements OnInit {
@Output() notify: EventEmitter<any> = new EventEmitter();
@Input() private allItems: Array<any>;
constructor() { }
ngOnInit() {
doSomething();
}
doSomething() {
this.notify.emit(allItems);
}
}
ベストアンサー1
記事ExpressionChangedAfterItHasBeenCheckedError
エラーについて知っておくべきことすべてこの行動を詳細に説明している
原因
あなたの問題は非常に似ていますこれにしかし、親プロパティをサービスを通じて更新するのではなく、同期イベントブロードキャストを通じて更新します。以下は、リンクされた回答:
ダイジェスト サイクル中、Angular は子ディレクティブに対して特定の操作を実行します。そのような操作の 1 つは、入力の更新と、子ディレクティブ/コンポーネントに対する ngOnInit ライフサイクル フックの呼び出しです。重要なのは、これらの操作が厳密な順序で実行されることです。
- 入力を更新する
- ngOnInitを呼び出す
したがって、あなたの場合、Angular はallItems
子コンポーネントの入力バインディングを更新し、次に子onInit
コンポーネントを呼び出し、親コンポーネントの更新を引き起こしましたallItems
。これでデータの不整合が発生しました。親コンポーネントには 1 つの値があり、子には別の値があります。Angular が変更の同期を続行すると、無限ループが発生します。これが、次の変更検出サイクルで Angular がallItems
変更されたことを検出し、エラーをスローした理由です。
解決
親コンポーネントと子コンポーネントの両方から更新しているため、これはアプリケーション設計上の欠陥であると思われますdetails
。そうでない場合は、次のようにイベントを非同期に発行することで問題を解決できます。
export class ChildComponent implements OnInit {
@Output() notify: EventEmitter<any> = new EventEmitter(true);
^^^^^^-------------
しかし、非常に注意が必要です。ngAfterViewChecked
ダイジェストサイクルごとに呼び出されるような他のフックを使用すると、循環依存に陥ってしまいます!