I have a form that is being instantiated programatically via DynamicComponentLoader::loadIntoLocation
. The form code is below:
constructor (
private _builder: FormBuilder
) {
this.editForm = _builder.group({
name: ['', Validators.required],
email: ['', Validators.compose([Validators.required, Helpers.emailValidator])],
phone: [''],
phoneAlt: [''],
location: [''],
dob: [''],
bio: [''],
});
}
You'll notice that some of the forms don't have validators (as far as I can tell, this is the same as using Validators.nullValidator
, I've tested with both).
In my template I have the following code (for each control):
<label for="phone">Contact Number <span *ngIf="!phone.valid">- {{e(phone)}}</span></label>
<input type="text" name="phone" id="phone" ngControl="phone" #phone="ngForm">
The first control that doesn't have a validator throws the following exception twice when it hits the !phone.valid
part of the template:
EXCEPTION: Expression '!phone.valid in e@15:43' has changed after it was checked. Previous value: 'true'. Current value: 'false' in [!phone.valid in e@15:43]
At no point am I touching the controls or this.editForm
after the initial creation, so, as far as my code is concerned, nothing should be changing.
I'm aware that I can suppress the errors by calling enableProdMode()
but I'd rather fix the problem than hide it.
Edit (8th Feb): I have since tried moving the contents of the modal to a separate page, but the errors persist. This would suggest the issue is not related to the way I am creating and loading the modals, but rather the ControlGroup or FormBuilder.
Plunker of the issue | Plunker without modal
Thanks to qdouble for solving this for me on the Angular Gitter chat.
The issue seemed to be caused by the order in which angular parsed the page. By going from top to bottom, ngIf="!phone.valid"
was being parsed before phone.valid
had been initialised. This was easily fixed by adding a catch in the if statement to make sure that it was not null *ngIf="phone.valid === null ? false : !phone.valid"
(or by moving the label after the input).
using ngAfterContentChecked fixed the error in my side
ngAfterContentChecked(): void {
this.cd.detectChanges();
}
This was the problem I ran into.
Angular 2 introduced a feature to better handle change detection. Angular 2 drops the digest cycles in favor of one-way flow which is about 3-10 times faster and handles asynchronous logic better.
@Component({
...
changeDetection: ChangeDetectionStrategy.OnPush
})...
Links: Angular Reference: https://angular.io/docs/ts/latest/api/core/index/ChangeDetectionStrategy-enum.html
Understanding change detection: https://auth0.com/blog/understanding-angular-2-change-detection/
How Angular 2 Change Detection Really Works: http://blog.angular-university.io/how-does-angular-2-change-detection-really-work/
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With