So I have a form where a control is required only if another control has a value, for this I created the following structure
profileGroup = this.fb.group({
username: [''],
address: [
'',
[
(control: AbstractControl) => {
if (this.profileGroup?.get('username')?.value) {
return (Validators.required)(control);
}
return (Validators.nullValidator)(control);
},
],
],
});
this function works well, once the username control gets a value, a Validators.required is added to the address control. However, despite the validator being added, the validity of the address control doesn't update so the control is still marked as valid.
If possible I would like to avoid using something like
this.profileGroup.get('username')?.valueChanges.subscribe(val=>{
this.profileGroup.get('address')?.updateValueAndValidity()
})
since there may be dynamic controls that I don't know the name of, and don't want to set an observable for each of them.
Here's a stack blitz of a working example https://stackblitz.com/edit/angular-10-formbuilder-example-m8qjq8?file=src/app/app.component.ts
Well, exactly that's not what happens. You have defined a
customvalidator foraddressFormControl, which gets executed when theaddressFormControl value is updated. (PS: It's not a dynamic validator)When you update the
username, the validators associated with it and its ancestors (profileGroup in your case) are called, the sibling FormControl validators are not triggered.When you execute the below code, you are manually executing the validators associated with
addressFormControl, and that doesn't update the FormControl validity. It simply executes the validators associated with the FormControl and return their result.In order to update the sibling i.e
addressFormControl validity, you will have to call it'supdateValueAndValidity().Another alternative could be to define validators at FormGroup level, which will be executed automatically and you don't have to manually call
updateValueAndValidity()on any FormControl. But, with this approach the validation errors will be set at FormGroup level.If you won't be aware of control names, how exactly you will be using them within custom validator as below, where
usernameFormControl is being referred?There is a way to call
updateValueAndValidity()on the formControl, without explicitly specifying it's name, BUT won't recommend it. You can loop over theprofileGroup.controlsand executeupdateValueAndValidityon each control, followed by profileGroup itself. You would also have to take care of passing{onlySelf: true, emitEvent: false}options toupdateValueAndValidityto avoid recursion.