Conditional Validation on Angular Reactive Form

January 9, 2023 • • Published By • 4 minute read

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.

Table of Contents

Angular Reactive Form

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

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

<input formControlName="phone" id="phone" name="phone" />

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" />

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]
});

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);
  });
}

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();
}

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();
    });
  }

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/)],

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();
    });
  }

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.

Related Articles
About the Author

Front End Developer

https://nightwolf.dev