I have a simple yet perplexing problem. I have a reactive form and I want to set validation programatically.
this.boatForm.get('boatType').setValidators(Validators.required);
this.boatForm.updateValueAndValidity();
this.boatForm.get('boatType').updateValueAndValidity();
this.#logger.debug(
'/n', 'value:', this.boatForm.get('boatType').value,
'/n', 'valid:', this.boatForm.get('boatType').valid
)
The value of the boatType control is null. Therefore I expect the log to show:
value: valid: false
And... it does.
But I have multiple controls on that form so instead of applying updateValueAndValidity() to each control individually, I want to execute:
this.boatForm.get('boatType').setValidators(Validators.required);
// Set other validators on other controls on the same form
this.boatForm.updateValueAndValidity();
this.#logger.debug(
'\n', 'value', this.boatForm.get('boatType').value,
'\n', 'valid', this.boatForm.get('boatType').valid
)
But now, I get:
value: valid: true
The work-around that we have implemented is to call a method:
static updateFormControlValidators(form: FormGroup): void {
// Iterate over each control in the form group
Object.keys(form.controls).forEach(controlName => {
const control = form.get(controlName);
// Call updateValueAndValidity to re-evaluate the validity of each control
if (control) {
control.updateValueAndValidity();
}
});
}
But the question is:
Should form.updateValueAndValidity() accomplish the same thing?
The docs mention:
updateValueAndValidity:
Recalculates the value and validation status of the control. By default, it also updates the value and validity of its ancestors.
To further support this, the documentation of AbstractControl
mentions to run the control's updateValueAndValidity
and not the root form.
AbstractControl - Docs (addValidators)
Sets the synchronous validators that are active on this control. Calling this overwrites any existing synchronous validators.
When you add or remove a validator at run time, you must call updateValueAndValidity() for the new validation to take effect.
If you want to add a new validator without affecting existing ones, consider using addValidators() method instead.
So when you update the form using updateValueAndValidity
, the form is the root ancestor, hence the child control is not updated.
this.boatForm.updateValueAndValidity();
When we update the control using updateValueAndValidity
, the control gets the required
validation applied and the root form also has it's recalculation of the value and validation status
.
this.boatForm.get('boatType')!.updateValueAndValidity();
So running the form's updateValueAndValidity
will update the validators of the root form and not the children.