ExpressionChangedAfterItHasBeenCheckedError` 错误 angular 4

ExpressionChangedAfterItHasBeenCheckedError` error angular 4

我正在尝试从事一个包含多个组件的项目。示例应用程序是 here。我在开发模式下遇到如下错误

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

Because after the child component values are bound , parent component values are updated by grandparent component, resulting in throwing of error during angular dirty check

我的应用程序的骨架是 here。有人可以帮我解决这个问题吗?我知道可以通过使用 setTimeout 或 changeDetectionRef 来解决。但这不是我正在寻找的解决方案,我想知道我在生命周期挂钩期间做错了什么。提前致谢。

很高兴听到您反对 setTimeout 并手动调用 detectChanges

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

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

Because after the child component values are bound , parent component values are updated by grandparent component, resulting in throwing of error during angular dirty check

看来你是对的,你的 child 组件在 ngAfterContentInit 发生之前呈现。

Angular 应用程序是一棵视图树。当 angular 运行变化检测机制时,它会遍历这个视图树并为每个视图调用 checkAndUpdateView 函数。

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

execEmbeddedViewsAction
callLifecycleHooksChildrenFirst (AfterContentInit)
execComponentViewsAction

表示angular会在执行ngAfterContentInit hook之前调用嵌入式视图的变更检测周期(ng-template生成嵌入式视图) .这就是您的示例中发生的情况:

正如我们在上图中看到的,当 angular 检查 AppComponent 视图时,它首先检查嵌入的视图,然后为 GrandParentComponent 调用 ngAfterContentInit 并下降到 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);
    }
  }

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

盛大parent.component.ts

export class GrandParentComponent {

  parents = [];