Conditional Validation on Angular Reactive Form

nightwolfdev - Jan 10 '23 - - Dev Community

Have you ever needed to make a specific form field required if the value of another form field changed? In this article, learn how to make a phone number field required if the contact preference field changes its value to phone call or text message. Also, learn how to avoid losing existing validation rules that are already in place.

Angular Reactive Form

Let’s say you have a form that looks like the following:

Angular Form

The input for the Phone Number field has a formControlName of phone.

<input formControlName="phone" id="phone" name="phone" />
Enter fullscreen mode Exit fullscreen mode

The radio buttons for the Contact Preference field have a formControlName of contactPreference. Also, make note of the values for each radio button: email, phone, text.

<input type="radio" formControlName="contactPreference" name="contactPreference" value="email" />

<input type="radio" formControlName="contactPreference" name="contactPreference" value="phone" />

<input type="radio" formControlName="contactPreference" name="contactPreference" value="text" />
Enter fullscreen mode Exit fullscreen mode

Within your form group, the form control names should match what you used in the form itself (phone, contactPreference).

this.form = this.formBuilder.group({
  firstName: ['', Validators.required],
  lastName: ['', Validators.required],
  email: ['', [Validators.required, Validators.email]],
  phone: '',
  contactPreference: ['email', Validators.required]
});
Enter fullscreen mode Exit fullscreen mode

The phone form control has no default value or validation, meaning the user does not have to define a value for the Phone Number field on the form. The contactPreference form control has a default value of email and it’s a required field because it’s using the required validator. However, as you saw on the form, the user can choose from the following options for Contact Preference:

  • Email
  • Phone Call
  • Text Message

If the user chooses Phone Call or Text Message, we want to make the Phone Number field required on the form.

Subscribe To Value Changes

We can watch for value changes on the entire form or on a specific form control. Let’s watch the contactPreference control for value changes. Create a function called onContactPreferenceChange and add the following:

private onContactPreferenceChange(): void {
  this.form.get('contactPreference').valueChanges.subscribe(value => {
    console.log(value);
  });
}
Enter fullscreen mode Exit fullscreen mode

Add the onContactPreferenceChange function to the ngOnInit lifecycle hook. This will subscribe to value changes to the Contact Preference field as soon as the component is created.

ngOnInit() {
  this.onContactPreferenceChange();
}
Enter fullscreen mode Exit fullscreen mode

If you have your browser’s Developer Tools open, you’ll see that every time you select a Contact Preference, it will log the value to the console.

Set/Clear Validators

We want to set the required validator on the phone control when the Contact Preference value changes to phone or text. If the Contact Preference value is email, we want to clear validators. Update the onContactPreferenceChange function to the following:

private onContactPreferenceChange(): void {
  this.form.get('contactPreference').valueChanges.subscribe(value => {
    const phoneControl = this.form.get('phone');
    const validators = [Validators.required];

    if (value === 'phone' || value === 'text') {
      phoneControl.setValidators(validators);
    } else {
      phoneControl.clearValidators();
    }

    phoneControl.updateValueAndValidity();
  });
}
Enter fullscreen mode Exit fullscreen mode

Now, when the user selects a Contact Preference of phone or text, we set the required validator on the phone control. If the user selects email, we clear all validators.

Because we’re updating the validators at run time, we must also call the updateValueAndValidity function in order for the validation changes to apply.

Add/Remove Validators

Currently, our phone control has no existing validators on it. What if it did? For example, what if it started with a validator that checks for a phone number pattern?

phone: ['', Validators.pattern(/PHONE_NUMBER_PATTERN/)],
Enter fullscreen mode Exit fullscreen mode

If we use setValidators, it overwrites any existing validators. When using clearValidators, it clears ALL validators. The better option would be to use addValidators and removeValidators.

private onContactPreferenceChange(): void {
  this.form.get('contactPreference').valueChanges.subscribe(value => {
    const phoneControl = this.form.get('phone');
    const validators = [Validators.required];

    if (value === 'phone' || value === 'text') {
      phoneControl.addValidators(validators);
    } else {
      phoneControl.removeValidators(validators);
    }

    phoneControl.updateValueAndValidity();
  });
}
Enter fullscreen mode Exit fullscreen mode

Now, when the user selects a Contact Preference of phone or text, we add the required validator instead of overwriting existing validators on the phone control. If the user selects email, we remove just the validator that was previously added.


Visit our website at https://nightwolf.dev and follow us on Twitter!

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .