Angular form updateValueAndValidity of all children controls
Solution 1
I had the same situation for me to update FormGroup | FormArray
at nested level controls.
check this out(worked for me):
/**
* Re-calculates the value and validation status of the entire controls tree.
*/
function updateTreeValidity(group: FormGroup | FormArray): void {
Object.keys(group.controls).forEach((key: string) => {
const abstractControl = group.controls[key];
if (abstractControl instanceof FormGroup || abstractControl instanceof FormArray) {
updateTreeValidity(abstractControl);
} else {
abstractControl.updateValueAndValidity();
}
});
}
Solution 2
It is not possible at the moment to update the descendants of an AbstractControl (FormGroup, ...) with the AbstractControl itself. Maybe in a future release it will be possible.
https://github.com/angular/angular/issues/6170
https://github.com/angular/angular/issues/22166
update: a pull request is already open https://github.com/angular/angular/pull/19829
Solution 3
I solved my issue, which was similar to yours, by recursing the controls and manually triggering the update. Probably this is not an optimal solution:
private triggerValidation(control: AbstractControl) {
if (control instanceof FormGroup) {
const group = (control as FormGroup);
for (const field in group.controls) {
const c = group.controls[field];
this.triggerValidation(c);
}
}
else if (control instanceof FormArray) {
const group = (control as FormArray);
for (const field in group.controls) {
const c = group.controls[field];
this.triggerValidation(c);
}
}
control.updateValueAndValidity({ onlySelf: false });
}
Solution 4
validateFormFields(fields) {
try {
Object.entries(fields.controls).forEach((control: any) => {
if (typeof control[0] == 'Array'
) {
this.validateFormFields(control[1]);
} else {
if (control[1].controls) {
Object.entries(control[1].controls).forEach((c: any) => {
c[1].touched = true;
});
} else {
control[1].touched = true;
}
}
});
} catch (e) {
console.log(e);
}
}
Solution 5
I ran into the same problem, one of the issues was that listening to the valueChanges
observable and triggering updateValueAndValidity
to run my validators caused an endless loop, so to resolve (and somewhat hacky ?) I created the component variable validityCycleFired
and initialized as false, that I toggle and it prevents a runaway loop:
const fireValidityCheck = () => {
if (this.validityCycleFired) return;
this.validityCycleFired = true;
this.passwordForm.get('old_password').updateValueAndValidity();
this.passwordForm.get('new_password').updateValueAndValidity();
this.passwordForm.get('confirm_new_password').updateValueAndValidity();
setTimeout(() => this.validityCycleFired = false, 15);
return;
};
this.passwordForm.valueChanges.subscribe(fireValidityCheck);
Comments
-
Francesco Borzi almost 2 years
In my Angular 4 app, I have a form with several controls.
At some points I need to force the update of their validity, so I'm doing:
this.form.get('control1').updateValueAndValidity(); this.form.get('control2').updateValueAndValidity(); this.form.get('control3').updateValueAndValidity(); // and so on....
and then:
this.form.updateValueAndValidity();
this works fine.
However I was wondering if there is a better way to accomplish the same thing, by just calling one method on the parent form.
According to its documentation, the
updateValueAndValidity()
method:By default, it will also update the value and validity of its ancestors.
but in my case I need to update the value and validity of its descendants. So I can get rid of many lines of code.
-
Emmanuel over 4 yearsMarking the control as touched is what was missing in other answers!