Angular 4 ExpressionChangedAfterItHasBeenCheckedError [英] Angular 4 ExpressionChangedAfterItHasBeenCheckedError

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

问题描述

在父组件中 =>

ExpressionChangedAfterItHasBeenCheckedError:表达式在检查后发生了变化.以前的值:''.当前值:'[object Object]'.在 viewDebugError (vendor.bundle.js:8962)在 expressionChangedAfterItHasBeenCheckedError (vendor.bundle.js:8940)

父组件 Html

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

父组件

export class ParentComponent 实现 OnInit {返回的项目:数组<任何>= [];allItems: Array= [];构造函数() { }ngOnInit() {this.allItems =//从服务器加载...}eventCalled(items: Array): void {this.returnedItems = 物品;}}

子组件

@Component({选择器:'app-child-widget',templateUrl: 'child.component.html',styleUrls: ['./child.component.css']})导出类 ChildComponent 实现 OnInit {@Output() 通知:EventEmitter= new EventEmitter();@Input() private allItems: Array;构造函数(){}ngOnInit() {做点什么();}做点什么() {this.notify.emit(allItems);}}

解决方案

文章 您需要了解的有关ExpressionChangedAfterItHasBeenCheckedError 错误的所有信息 详细解释了这种行为

原因

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

<块引用>

在摘要循环期间,Angular 会对子进程执行某些操作指令.其中一项操作是更新输入和调用ngOnInit 生命周期挂钩子指令/组件.什么是重要的是这些操作是按照严格的顺序执行的:

  • 更新输入
  • 调用 ngOnInit

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

解决方案

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

导出类 ChildComponent 实现 OnInit {@Output() 通知:EventEmitter= 新事件发射器(真);^^^^^^-------------

但是你必须非常小心.如果您使用任何其他钩子,例如在每个摘要循环中调用的 ngAfterViewChecked您将最终陷入循环依赖!

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

Parent component Html

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

Parent component

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

Child component

@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

Cause

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:

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:

  • Update inputs
  • Call ngOnInit

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.

Solution

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);
                                                        ^^^^^^-------------

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天全站免登陆