当投影组件在祖先中设置值时,“检查​​后更改”错误

时间:2018-03-15 22:15:52

标签: angular

当投影组件在祖先组件中设置值时,我收到“检查后更改”错误。以下是我的问题的复制品:plnkr.co/edit/jJNFsJdf1KDSF3Fqhfb8

@Component({
  selector: 'app-component',
  template: `
    <test-component>
      <ng-template #tpl>
        <projected-component [rootComponent]="this"></projected-component>
      </ng-template>
    </test-component>
    {{change}}
  `
})
export class AppComponent {
  change = 0;
}


@Component({
  selector: 'test-component',
  template: `
    <ng-template [ngTemplateOutlet]="tplRef"></ng-template>
  `
})
export class TestComponent {
  @ContentChild('tpl') tplRef: TemplateRef<any>;
}


@Component({
  selector: 'projected-component',
  template: ` 
    <div>{{parent}}</div>
  `
})
export class ProjectedComponent {
  @Input() rootComponent: TestApp;

  ngOnInit() {
    this.rootComponent.change++;
  }
}

错误是:

ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'null: 0'. Current value: 'null: 1'.

我首先是由Matt Brophy的nested form pattern来解决这个问题。这是一个美丽的模式,但我认为他可能忽略了这个问题,或者它在早期版本的Angular中不是问题。我原来的问题是here。由于我没有简化的实时复制,因此我没有成功获得解决方案的帮助。

如何在不出错的情况下进行设置?

1 个答案:

答案 0 :(得分:2)

问题是您是在同一个更改检测周期中更改父级的数据。您可以通过简单地将更改包装在setTimeout()调用中来阻止该错误被抛出,以确保它在更改检测周期完成后运行。

ngOnInit() {
    console.log(this.rootComponent);
    setTimeout(() => this.rootComponent.change++);
}

您通常不会遇到这些问题,因为它通常是一些触发数据更改的用户事件,而不是在更改检测生命周期中运行的某些方法(至少不会更改父数据)。

话虽如此,但通常不应修改由另一个组件拥有的数据。正如@Harry Ninh所提到的,最好广播一个事件来通知父母需要更新数据(在这种情况下,你仍然需要用setTimeout()包装,因为你仍然会广播在同一个更改检测周期中更改父级数据的事件。)