Angular 4 ExpressionChangedAfterItHasBeenCheckedError

Sau*_*mar 19 typescript angular-components angular

在ParentComponent =>中

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)
Run Code Online (Sandbox Code Playgroud)

父组件Html

<div>
  <app-child-widget [allItems]="allItems" (notify)="eventCalled($event)"></app-child-widget>
<div>
Run Code Online (Sandbox Code Playgroud)

父组件

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;
  }
}
Run Code Online (Sandbox Code Playgroud)

儿童组件

@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);
  }
}
Run Code Online (Sandbox Code Playgroud)

Max*_*kyi 31

文章关于ExpressionChangedAfterItHasBeenCheckedError错误需要知道的所有内容都会详细解释这种行为

原因

您的问题与问题非常相似,但不是通过服务更新父属性,而是通过同步事件广播更新它.以下是链接答案的引用:

在摘要周期中,Angular对子指令执行某些操作.其中一个操作是更新输入并在子指令/组件上调用ngOnInit生命周期钩子.重要的是这些操作是按严格的顺序执行的:

  • 更新输入
  • 调用ngOnInit

因此,在您的情况下,Angular更新allItems了对子组件的输入绑定,然后onInit在子组件上调用,这导致allItems父组件的更新.现在您有数据不一致.父组件具有一个值,而子组件具有另一个值.如果Angular继续同步更改,您将获得无限循环.这就是为什么在下一个更改检测周期中,Angular检测到allItems更改并抛出错误.

当您details从父组件和子组件更新时,这似乎是一个应用程序设计缺陷.如果不是,那么您可以通过异步发出事件来解决问题,如下所示:

export class ChildComponent implements OnInit {
  @Output() notify: EventEmitter<any> = new EventEmitter(true);
                                                        ^^^^^^-------------
Run Code Online (Sandbox Code Playgroud)

但你必须非常小心.如果您使用任何其他钩子,就像ngAfterViewChecked在每个摘要周期中调用它一样,您将最终处于循环依赖状态!

  • `new EventEmitter(true)` (5认同)