24sharon
24sharon

Reputation: 1975

angular reactive form conditionally validate fields based on another field's value

This is my code

detailsGroup = new FormGroup({
    userId:new FormControl('1'),
    firstName: new FormControl('', Validators.required),
    lastName: new FormControl('', Validators.required),
    email: new FormControl('',[ Validators.required, Validators.email]),
  });

I want if the userId equal to 1 then the firstname last name and email does not required otherwise those 3 fields change to required and the email also validate the email adress.

Thanks

Upvotes: 5

Views: 12330

Answers (3)

Hamid
Hamid

Reputation: 897

I'm just going to share my sample code which tends to demonstrate how we apply validation for a form filed based on another filed value, in this sample I'm going to apply a validator for sectorId, if doesContainDemo filed value being true.

 private _buildForm(): void {
    this.storeForm = this._fb.group({
      name: [
        '',
        Validators.compose([
          Validators.required,
          Validators.minLength(3)
        ])
      ],
      doesContainDemo: [true],
      sectorId: ['', this._sectorValidator()],
    });
  }

SectorValidator is like the below

 private _sectorValidator(): ValidatorFn {
    return (control: AbstractControl): { [key: string]: any } | null => {
      const doesContainDemo = this.storeForm?.controls['doesContainDemo'].value;
      const storeSector = this.storeForm?.controls['sectorId'].value;
      if (doesContainDemo === true && !storeSector) {
        return { conditionalRequired: true };
      }
      return null;
    };
  }

Upvotes: 0

vicnoob
vicnoob

Reputation: 1183

You should write a custom validator, something like this: Demo: https://angular-custom-validator-p2u1jv.stackblitz.io

function nameValidator(form: FormGroup): ValidatorFn {
  return (control: AbstractControl): ValidationErrors | null => {
    const needRequire = form.get('userId').value != 1
    const noValue = needRequire ? !(control.value) : false
    return noValue ? {required: control.value} : null;
  };
}
this.form = new FormGroup({
  userId:new FormControl('1'),
  firstName: new FormControl(''),
  lastName: new FormControl(''),
  email: new FormControl('',[ Validators.required, Validators.email]),
});

this.form.get('firstName').setValidators(nameValidator(this.form))
this.form.get('lastName').setValidators(nameValidator(this.form))

Upvotes: 6

Manish
Manish

Reputation: 5066

In order to achieve this you can use the setValidators and clearValidtors methods available with the FormControl class. Below is how you can use them to dynamically add or remove validators from a particular control of the form. Also the setValidators method takes either a single validator or an array of validators as parameters, so in case of email you can use it like this

this.detailsForm.get('email').setValidators([Validators.required,Validators.email]);

Since angular provides both the required and the email validators, you won't have to write any custom validator functions.

import { Component, OnInit, VERSION } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
})
export class AppComponent implements OnInit {
  name = 'Angular ' + VERSION.major;
  detailsForm: FormGroup;
  validation: boolean;
  constructor(private formBuilder: FormBuilder) {}

  ngOnInit() {
    this.detailsForm = this.formBuilder.group({
      userId: ['', [Validators.required]],
      firstName: ['', [Validators.required]],
      lastName: ['', [Validators.required]],
      email: ['', [Validators.required]],
    });
    this.detailsForm.get('userId').valueChanges.subscribe(() => {
      const val = this.detailsForm.getRawValue();
      if (val.userId.toString() === '1') {
        Object.keys(this.detailsForm.controls).forEach((controlName) => {
          this.detailsForm.controls[controlName].clearValidators();
          this.detailsForm.controls[controlName].updateValueAndValidity();
        });
      } else {
        Object.keys(this.detailsForm.controls).forEach((controlName) => {
          this.detailsForm.controls[controlName].setValidators(
            Validators.required
          );
          this.detailsForm.controls[controlName].updateValueAndValidity();
        });
      }
      this.validation = this.detailsForm.get('email').valid;
    });
  }
}

Here is a working demo of the same. If you type 1 email has no validators and is found valid. If you type any other value the email control becomes invalid.

You can play with the above editable code here

Upvotes: 3

Related Questions