ExpressionChangedAfterItHasBeenCheckedError`错误角度4

时间:2018-01-19 14:32:52

标签: angular angular2-template angular2-services

我正在尝试处理具有多个组件的项目。示例应用是here。我处于这样一种情况,我在开发模式中得到如下错误

Error

我知道为什么会出现这个错误

  

因为在子组件值绑定后,父组件   值由祖父组件更新,导致抛出   角度脏检查时出错

我的应用的骨架是here。有人可以帮我解决这个问题。我知道它可以通过使用setTimeout或changeDetectionRef来解决。但那不是我想要的解决方案,我想知道在生命周期钩子中我做错了什么。提前谢谢。

1 个答案:

答案 0 :(得分:2)

很高兴听到您反对setTimeout并手动拨打detectChanges

我知道这在您的应用结构中很明显,但这里有一个示例,可以显示错误的来源:

https://ng-run.com/edit/d9EEfZLhGfM0fYQtehhs?open=app%2Fgrandparent%2Fparent%2Fchild%2Fchild.component.html&layout=2

  

因为在子组件值绑定后,父组件   值由祖父组件更新,导致抛出   角度脏检查时出错

似乎你在ngAfterContentInit发生之前渲染了你的子组件。

Angular应用程序是一个视图树。当角度运行改变检测机制时,它会通过这个视图,并为每个视图调用checkAndUpdateView函数。

在执行此函数期间,angular以严格定义的顺序调用其他函数。在我们的案例中,我们对这些功能感兴趣:

execEmbeddedViewsAction
callLifecycleHooksChildrenFirst (AfterContentInit)
execComponentViewsAction

这意味着 angular将比执行ng-template hook 更早地调用嵌入视图的更改检测周期(ngAfterContentInit生成嵌入视图)。这就是你的例子中发生的事情:

enter image description here

正如我们在上图中看到的,当角度检查AppComponent视图时,它首先检查嵌入的视图,然后调用ngAfterContentInit GrandParentComponent并向下查看GrandParentComponent

似乎有很多方法可以解决它。我在 Demo

中试用了它们

关键时刻不使用ngAfterContentInit挂钩,而是在ParentComponent中设置索引和有效值:

<强> parent.component.ts

export class ParentComponent {
  private _active: boolean = false;
  public index = 0;

  constructor(
      @Host() @Inject(forwardRef(() => GrandParentComponent))
      public grandParentComponent: GrandParentComponent) {
    this.index = this.grandParentComponent.parents.length;
    this.grandParentComponent.parents.push(this)
  }

  ngOnInit() {
    this.active = this.index == this.grandParentComponent.currentStep;
  }

  ngOnDestroy() {
    if (this.grandParentComponent) {
      this.grandParentComponent.parents = this.grandParentComponent.parents.filter(x => x !== this);
    }
  }

其中parent属性已在GrandParentComponent中声明:

<强> grandparent.component.ts

export class GrandParentComponent {

  parents = [];