ExpressionChangedAfterItHasBeenCheckedError from Angular

This is a continuation of my original version

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

which is still not resolved. I recreated the orignal plunkr to simulate an actual project and found it had nothing to do with the textbox.

When I go to the details page by clicking on an item from the list, an ExpressionChangedAfterItHasBeenCheckedError is thrown . This only happens when the CodeView src / detailitems.ts has more than one item in the array. CodeView elements define fields in a detailed 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 change the code so that the CodeView only has 1 item, the exception is gone.

Exception Plunkr

No Exception Plunkr (Only one item in detailitems)

+3


source to share


1 answer


Your error comes from A-Item

component more accurately from this node

<div [formGroup]="form"

      

when you have such a binding angular will automatically create a directive NgControlStatusGroup

that sets the CSS classes based on the control state (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',
};

      

The first time, you don't provide any values ​​for your controls. For this, a valid

property for your form false

. You then populate it using ngModel

change detection during the cycle and the form becomes valid. The valid property for is form

calculated from all of your controls. If you only have one control, then the actual property will only depend on one control, and the component A-Item

will not throw errors.

I would prepare the 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 fix the data for the 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 in sync with your value and have the correct status.

In this case, you can also remove the components from itemValue

and ngModel

from A-Item

, as the reactive model will work.

Forked plunker

You won't get this error

Another tip:

import * as Rx from 'rxjs/Rx'

      

you will send the whole rxjs library to your package

+3


source







All Articles