Angular 4 ExpressionChangedAfterItHasBeenCheckedError [英] Angular 4 ExpressionChangedAfterItHasBeenCheckedError

查看:100
本文介绍了Angular 4 ExpressionChangedAfterItHasBeenCheckedError的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在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)

父项HTML

<div>
  <app-child-widget [allItems]="allItems" (notify)="eventCalled($event)"></app-child-widget>
<div>

父项

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;
  }
}

子组件

@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);
  }
}

推荐答案

文章

The article Everything you need to know about the ExpressionChangedAfterItHasBeenCheckedError error explains this behavior in great details

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

Your problem is very similar to this one but instead of updating parent property through a service you're updating it through synchronous event broadcasting. Here is the quote from the linked answer:

在摘要周期中,Angular对子代执行某些操作 指令.这些操作之一是更新输入并调用 ngOnInit生命周期挂钩在子指令/组件上.什么是 重要的是这些操作必须严格执行:

During digest cycle Angular performs certain operations on child directives. One of such operations is updating inputs and calling ngOnInit lifecycle hook on child directives/components. What's important is that these operations are performed in strict order:

  • 更新输入
  • 致电ngOnInit

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

So in your case Angular updated input binding allItems on child component, then called onInit on child component which caused an update to allItems of parent component. Now you have data inconsistency. Parent component has one value while the child another. If Angular continues synchronizing changes you'll get an infinite loop. That's why during next change detection cycle Angular detected that allItems was changed and thrown an error.

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

It seems that this is an application design flaw as you're updating details from both parent and child component. If it's not, then you can solve the problem by emitting the event asynchronously like this:

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

但是您必须非常小心.如果您在每个摘要周期使用诸如ngAfterViewChecked之类的任何其他钩子,则您将最终陷入循环依赖!

But you have to be very careful. If you use any other hook like ngAfterViewChecked that is being called on every digest cycle, you'll end up in cyclic dependency!

这篇关于Angular 4 ExpressionChangedAfterItHasBeenCheckedError的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆