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.
No Exception Plunkr (Only one item in detailitems)
source to share
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.
You won't get this error
Another tip:
import * as Rx from 'rxjs/Rx'
you will send the whole rxjs library to your package
source to share