【问题标题】:ExpressionChangedAfterItHasBeenCheckedError from Angular来自 Angular 的 ExpressionChangedAfterItHasBeenCheckedError
【发布时间】:2017-12-14 17:59:44
【问题描述】:

这是我原来的问题的延续

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

这仍然没有解决。我重新创建了原始 plunkr 来模拟实际项目,发现它与 textarea 无关。

当我通过单击列表中的项目进入详细信息页面时,抛出异常 ExpressionChangedAfterItHasBeenCheckedError。仅当 src/detailitems.ts 的 CodeView 在数组中有多个元素时才会发生这种情况。 CodeView 项以详细形式定义字段。

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

}

如果我修改代码使 CodeView 只有 1 项,那么异常就会消失。

Exception Plunkr

No Exception Plunkr(仅详细一项)

【问题讨论】:

标签: angular exception


【解决方案1】:

您的错误来自A-Item 组件,更准确地说来自此节点

<div [formGroup]="form"

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

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

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

我会在渲染之前准备数据。

你可以打开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(new formObjectItem(item, this.getData(item.key)));
   group[item.key].patchValue(this.getData(item.key)); // <== this line
});

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

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

在这种情况下,您还可以从 A-Item 组件中删除 itemValuengModel,因为响应式模型将完成所有工作。

Forked Plunker

你不会得到这样的错误

还有一个提示:

import * as Rx from 'rxjs/Rx'

您会将所有 rxjs 库发送到您的捆绑包中

【讨论】:

  • 谢谢。当我调试时,core.umd.js 中的 view.oldValues[def.bindingIndex + bindingIdx] 指向“有效”标志导致了问题。因此,出于测试目的,我尝试为 valid() 调用始终返回 true,但这并没有帮助删除 A-Item 的类,所以我继续前进。当表单只有一个字段时我没有为控件设置值时,为什么只有当表单有多个字段时才会触发此异常?
  • 当它只有一个字段时,它在A-Item 模板检查期间变得稳定。但是,如果您有多个字段,则每个字段都不知道其他字段。 Angular 检查第一个字段,并且由于表单由多个控件组成,因此在检查当前字段视图后,表单的有效状态仍然是 false。然后角度移动以检查第二个字段并填充第二个控件的值,以便表单变得有效。最后 angular 运行 checkNoChanges 并再次检查 form.valid。 (假=>真)
  • 我正在剥离和切割 A-Item 组件,因为异常显示是从那里抛出的,但实际上它来自 A-Form。您曾建议 A-item 中不需要 itemValue 和 ngModel,但是当我从 A-Item 中删除 @input() itemValue 和从 A-Form 模板中删除 &lt;A-Item [item]="item.anItem" [form]="form" [itemValue]="item.itemValue"&gt;&lt;/A-Item&gt; 时,表单控件出现空 -> plunker
  • 你也应该删除[(ngModel)]检查这个更新plnkr.co/edit/ankcAjsXjybHi8tB6Q3W?p=preview
  • 知道了。我想补充一点,因为之前的异常,变更检测也搞砸了。因此,当我在详细信息中单击“保存”并返回列表页面时,该页面将显示一个只有标题的空白列表,并且应该在列表页面中启用的下拉列表仍然处于禁用状态。现在,在解决了异常之后,这一切都得到了解决。再次感谢您。
猜你喜欢
  • 2017-11-25
  • 2018-01-20
  • 1970-01-01
  • 2018-03-05
  • 2017-11-07
  • 2021-01-02
  • 1970-01-01
  • 2022-11-22
  • 2018-02-03
相关资源
最近更新 更多