ExpressionChangedAfterItHasBeenCheckedError from Angular [英] ExpressionChangedAfterItHasBeenCheckedError from Angular

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

问题描述

这是我原来问题的延续



stackoverflow.com/questions/44596418/angular-throws-expressionchangedafterithasbeencheckederror-with-textarea



其中尚未解决。我重新创建了orignal plunkr来模拟实际的项目,发现它与textarea无关。



当我从列表中点击一个项目去详细页面时,抛出异常 ExpressionChangedAfterItHasBeenCheckedError 。只有当 src / detailitems.ts 的CodeView在数组中有多个元素时才会发生这种情况。 CodeView项目以详细的形式定义了这些字段。

 从'./formbase'导入{FormBase} 
import { ItemBase,TextboxItemBase} from'./itembase'

export class CodeView扩展FormBase {

static getItems():ItemBase [] {

let项目:ItemBase [] = [

new TextboxItemBase(
{
key:'id',
label:'ID',
value:' ',
required:true,
enabled:false,
readOnly:true,
size:36
}


new TextboxItemBase(
{
key:'description',
label:'Description',
required:true,
size:20

}

];

返回项目;
}

}

如果我修改代码, CodeView只有1个项目,然后异常消失。



Exception Plunkr



No Exception Plunkr (only one item in detailitems)

解决方案

您的错误从 A-Item 组件更精确地从该节点

 < div [formGroup] =form

当你有这样的绑定角度会自动创建根据控制状态(有效/无效/脏/等)设置CSS类的NgControlStatusGroup 指令。

  export const ngControlStatusHost = {
'[class.ng-untouched]':'ngClassUntouched',
'[class.ng-touch ]':'ngClassTouched',
'[class.ng-pristine]':'ngClassPristine',
'[class.ng-dirty]':'ngClassDirty',
'[class .ng-valid]':'ngClassValid',//你收到这个绑定的错误
'[class.ng-invalid]':'ngClassInvalid',
'[class.ng-pending] :'ngClassPending',
};

第一次,您不会为控件提供任何值。这就是为什么您的表单有效属性为 false 。然后在更改检测周期中使用 ngModel 填充它,并且形式为有效。 表单的有效属性由您的所有控件计算。如果您只有一个控件,则有效属性将仅取决于一个控件, A-Item 组件不会引起错误。


$ b $我将在渲染之前准备数据。



您可以打开 form.component.ts ,并找到以下代码

  this.formItems.forEach(item => {
group [item.key] = item.BuildControl();
this.items.push(new formObjectItem item,this.getData(item.key)));
});

然后您需要修补数据表单

  this.formItems.forEach(item => {
group [item.key] = item.BuildControl();
this.items.push formObjectItem(item,this.getData(item.key)));
group [item.key] .patchValue(this.getData(item.key)); //< ==这行
});

  this.formItems.forEach(item => {
group [item.key] = item.BuildControl();
const value = this.getData(item.key);
this.items.push(new formObjectItem(item,value));
group [item.key] .patchValue(value);
});

这样,您的表单将与您的值同步并具有正确的状态。



在这种情况下,您还可以从<$ c中删除 itemValue ngModel $ c> A-Item 组件,因为反应模型将全部工作。



Forked Plunker



你没有得到这样的错误



还有一个提示:

 导入*作为Rx从'rxjs / Rx'

您将所有rxjs库发送到您的包


This is continuation to my original issue

stackoverflow.com/questions/44596418/angular-throws-expressionchangedafterithasbeencheckederror-with-textarea

which is still unresolved. I recreated the orignal plunkr to simulate the actual project and found it is nothing related to the textarea.

When I go to details page by clicking on a item from the list,the exception ExpressionChangedAfterItHasBeenCheckedError is thrown. This happens only when the CodeView of src/detailitems.ts has more than one element in the array. The CodeView items defines the fields in detail form.

import { FormBase } from './formbase'
import { ItemBase, TextboxItemBase } from './itembase'

export class CodeView extends FormBase {

    static getItems() :ItemBase[] {

    let items: ItemBase[] = [

        new TextboxItemBase(
            {
                key: 'id',
                label: 'ID',
                value: '',
                required: true,
                enabled: false,
                readOnly: true,
                size: 36
            }
        )
,
        new TextboxItemBase(
            {
                key: 'description',
                label: 'Description',
                required: true,
                size: 20

            }
        )            
    ];

    return items;
}

}

If I modify the code so that the CodeView has only 1 item, then the exception goes away.

Exception Plunkr

No Exception Plunkr (Just one item in detailitems)

解决方案

Your error comes from A-Item component more precisely from this node

<div [formGroup]="form"

when you have such binding angular will automatically create NgControlStatusGroup directive that sets CSS classes based on control status (valid/invalid/dirty/etc).

export const ngControlStatusHost = {
  '[class.ng-untouched]': 'ngClassUntouched',
  '[class.ng-touched]': 'ngClassTouched',
  '[class.ng-pristine]': 'ngClassPristine',
  '[class.ng-dirty]': 'ngClassDirty',
  '[class.ng-valid]': 'ngClassValid', // you get error in this binding
  '[class.ng-invalid]': 'ngClassInvalid',
  '[class.ng-pending]': 'ngClassPending',
};

At first time you don't provide any value for your controls. That's why valid property for your form is false. Then you populate it by using ngModel during change detection cycle and form becames valid. Valid property for form is calculated from all your controls. If you have only one control then valid property will depend only on one control and A-Item component won't raise error.

I would prepare data before rendering.

You can open form.component.ts and find the following code

this.formItems.forEach(item => {
   group[item.key] = item.BuildControl();
   this.items.push(new formObjectItem(item, this.getData(item.key)));
});

then you need to patch data for form

this.formItems.forEach(item => {
   group[item.key] = item.BuildControl();
   this.items.push(new formObjectItem(item, this.getData(item.key)));
   group[item.key].patchValue(this.getData(item.key)); // <== this line
});

or

this.formItems.forEach(item => {
   group[item.key] = item.BuildControl();
   const value = this.getData(item.key);
   this.items.push(new formObjectItem(item, value));
   group[item.key].patchValue(value);
});

This way your form will be synchronized with your value and will have correct status.

In this case you can also remove itemValue and ngModel from A-Item component since reactive model will do all work.

Forked Plunker

You don't get such error

One more tips:

import * as Rx from 'rxjs/Rx'

you will ship all rxjs library to your bundle

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

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