I'm submitting a...
Current behavior
If you have a composite form control (think a <my-address [formControl]="address"></my-address> component), if the internal form has a dynamic validator (i.e. [required]="isUSA"), the control will throw an ExpressionChangedAfterItHasBeenCheckedError error when the validator (in this example, isUSA value) changes:
Error: ExpressionChangedAfterItHasBeenCheckedError:
Expression has changed after it was checked.
Previous value: 'ng-valid: true'. Current value: 'ng-valid: false'.
Expected behavior
There to not be an ExpressionChangedAfterItHasBeenCheckedError error.
Minimal reproduction of the problem with instructions
Click on the Toggle Requiredness button, and note in the console that there is an ExpressionChangedAfterItHasBeenCheckedError error. (The circular JSON error seems to be generated from StackBitz.)
Demo: https://stackblitz.com/edit/angular-d9rsnv?file=app%2Fmy-composite-control%2Fmy-composite-control.component.ts
What is the motivation / use case for changing the behavior?
Template driven forms are easier to use, and template-driven (aka directive) validators are easier to work with and conditionally add and remove. You can do this similarly with reactive forms and you don't get this error.
Environment
Angular version: 5.2.8
Browser:
- [x] Firefox (desktop) version 59.0.3
Other information
Note that if you change the toggleRequiredness method to update the validators on the control, you don't get the error (but the point of this bug is that it should work by using purely template-driven means). For example, remove the required attribute from the input in the demo link above and update the toggleRequiredness method to this:
toggleRequiredness() {
this.nameRequired = !this.nameRequired;
const control = this.form.controls['name'];
if (this.nameRequired) {
control.setValidators([Validators.required]);
} else {
control.clearValidators();
}
control.updateValueAndValidity();
}
Demo (with the above modification): https://stackblitz.com/edit/angular-hhgkje?file=app%2Fmy-composite-control%2Fmy-composite-control.component.ts
Alternatively, you can manually trigger this.cdr.detectChanges(); when updating the requiredness. The argument of this bug is that this sort of behavior shouldn't be necessary with this kind of template-driven form.
Other reports related to validity changes during template execution
Specifically for validity, there does seem to be a potential to address this with a computed since the true/false value should not thrash by the end of the change detection (e.g. flip between true and false at the end of each cycle) and cause an infinite loop. errors/value/etc could cause infinite loops due to object equality and no clear way to compare values between separate change detection runs.
I'm submitting a...
Current behavior
If you have a composite form control (think a
<my-address [formControl]="address"></my-address>component), if the internal form has a dynamic validator (i.e.[required]="isUSA"), the control will throw anExpressionChangedAfterItHasBeenCheckedErrorerror when the validator (in this example,isUSAvalue) changes:Expected behavior
There to not be an
ExpressionChangedAfterItHasBeenCheckedErrorerror.Minimal reproduction of the problem with instructions
Click on the
Toggle Requirednessbutton, and note in the console that there is anExpressionChangedAfterItHasBeenCheckedErrorerror. (The circular JSON error seems to be generated from StackBitz.)Demo: https://stackblitz.com/edit/angular-d9rsnv?file=app%2Fmy-composite-control%2Fmy-composite-control.component.ts
What is the motivation / use case for changing the behavior?
Template driven forms are easier to use, and template-driven (aka directive) validators are easier to work with and conditionally add and remove. You can do this similarly with reactive forms and you don't get this error.
Environment
Other information
Note that if you change the
toggleRequirednessmethod to update the validators on the control, you don't get the error (but the point of this bug is that it should work by using purely template-driven means). For example, remove therequiredattribute from theinputin the demo link above and update thetoggleRequirednessmethod to this:Demo (with the above modification): https://stackblitz.com/edit/angular-hhgkje?file=app%2Fmy-composite-control%2Fmy-composite-control.component.ts
Alternatively, you can manually trigger
this.cdr.detectChanges();when updating the requiredness. The argument of this bug is that this sort of behavior shouldn't be necessary with this kind of template-driven form.Other reports related to validity changes during template execution
Specifically for validity, there does seem to be a potential to address this with a computed since the true/false value should not thrash by the end of the change detection (e.g. flip between
trueandfalseat the end of each cycle) and cause an infinite loop. errors/value/etc could cause infinite loops due to object equality and no clear way to compare values between separate change detection runs.