【问题标题】:ExpressionChangedAfterItHasBeenCheckedError` error angular 4ExpressionChangedAfterItHasBeenCheckedError`错误角度4
【发布时间】:2018-01-20 04:27:16
【问题描述】:

我正在尝试处理具有多个组件的项目。示例应用程序是here。我在开发模式中遇到如下错误的情况

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

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

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

【问题讨论】:

    标签: angular angular2-template angular2-services


    【解决方案1】:

    很高兴听到您反对 setTimeout 并手动致电 detectChanges

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

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

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

    看来你是对的,你的子组件是在 ngAfterContentInit 发生之前渲染的。

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

    在这个函数的执行过程中,Angular 会按照严格定义的顺序调用其他函数。在我们的例子中,我们对这些函数很感兴趣:

    execEmbeddedViewsAction
    callLifecycleHooksChildrenFirst (AfterContentInit)
    execComponentViewsAction
    

    这意味着angular会在执行ngAfterContentInit钩子之前调用嵌入视图的变化检测循环(ng-template生成嵌入视图)。这就是您的示例中发生的情况:

    正如我们在上图中看到的,当 Angular 检查 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);
        }
      }
    

    GrandParentComponent 中声明了父属性的位置:

    grandparent.component.ts

    export class GrandParentComponent {
    
      parents = [];
    

    【讨论】:

    • 感谢您的详细回答.. 真的帮助了我的理解:) 只是一个后续问题,.. 如果我必须在设置活动步骤之前检查一个条件,ng-run.com/edit/… .. 如何我能做到吗,因为父母没有初始化
    • 您可以将length 或整个obj 传递给祖父母。您也可以通过ng-content 让祖父母负责渲染子代而不进行转换。如果你想在这种情况下提供模板,那么你可以使用 ng-template 和 ngTemplateOutlet 指令
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-12
    • 2021-07-22
    • 2019-01-06
    • 2018-09-17
    • 2019-01-28
    • 2018-12-31
    相关资源
    最近更新 更多