I am trying to add and remove validators in a formGroup
controls based on certain condition.
When I am updating the validators through formGroup.updateValueAndValidity()
for whole form its not updating, where as if I am specifically applying for each Control i.e. formGroup.get('formControl').updateValueAndValidity()
, it is working but i have to write for each control which is i hope not the correct way. What am i doing wrong?
if (data == 'x') {
this.myForm.get('control2').setValue(null);
this.myForm.get('control2').setValidators(Validators.nullValidator);
this.myForm.get('control1').setValidators(Validators.required);
} else if (data == 'y') {
this.myForm.get('control1').setValue(null);
this.myForm.get('control1').setValidators(Validators.nullValidator);
this.myForm.get('control2').setValidators(Validators.required);
}
this.myForm.get('control1').updateValueAndValidity();
this.myForm.get('control2').updateValueAndValidity();
this is working, but,
this.myForm.updateValueAndValidity();
this is not working.
As Serginho said in the accepted answer, the problem is that updateValueAndValidity method is bottom-up, so it will not validate children controls. A possible solution for that is to write a custom prototype method for the FormGroup class like this:
import { FormGroup, FormControl } from '@angular/forms';
declare module '@angular/forms/forms' {
interface FormGroup {
validate(): void;
}
}
FormGroup.prototype.validate = function(this: FormGroup): void {
for (const key in this.controls) {
const formElement = this.get(key);
if (formElement instanceof FormControl) {
formElement.updateValueAndValidity();
} else if (formElement instanceof FormGroup) {
formElement.validate();
}
}
};
validate is a recursive method that call updateValueAndValidity for each leaf (FormControl) of the tree (FormGroup), even in case of nested form groups.
Don't forget to import your module where you need to use the validate method:
import '../core/extensions/formGroup';
updateValueAndValidity()
is bottom-up, so if you call this method over a control, it will check only validations of this control and their parents, but not their children.
For more details, see AbstractControl#updateValueAndValidity on github to how it works.
updateValueAndValidity(opts: {onlySelf?: boolean, emitEvent?: boolean} = {}): void {
this._setInitialStatus();
this._updateValue();
if (this.enabled) {
this._cancelExistingSubscription();
(this as{errors: ValidationErrors | null}).errors = this._runValidator();
(this as{status: string}).status = this._calculateStatus();
if (this.status === VALID || this.status === PENDING) {
this._runAsyncValidator(opts.emitEvent);
}
}
if (opts.emitEvent !== false) {
(this.valueChanges as EventEmitter<any>).emit(this.value);
(this.statusChanges as EventEmitter<string>).emit(this.status);
}
if (this._parent && !opts.onlySelf) {
this._parent.updateValueAndValidity(opts);
}
}
I stumbled upon this last week too, and I came to the conclusion that this is the expected behavior. The docs states the following:
By default, it also updates the value and validity of its ancestors.
Note that it says "ancestor" and not "descendants". This means that when you have run updateValueAndValidity()
on control1
and control2
, and they're both valid, myForm
will be marked as valid too.
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