Home > Net >  How can I change the validations based on previous field input angular
How can I change the validations based on previous field input angular

Time:12-21

I have two fields in reactive form in angular. I need to validate second field and show error message based on first field option chosen.

Field one:

<label>ID proof </b><span >*</span></label>
   <mat-form-field appearance="outline">
     <mat-select name="idproofs" placeholder="IDProof name" required formControlName="idProof" >
     <mat-option *ngFor="let idproof of idproofs" [value]="idproof.value">
        {{idproof.viewValue}}
     </mat-option>
     </mat-select>
  </mat-form-field>

Field two:

<label>ID proof number </b><span >*</span></label>
    <mat-form-field appearance="outline">
       <input matInput placeholder="ID Proof Number" required formControlName="idFroofNumber" >
    <mat-error *ngIf="PGroup.controls['idProofNumber'].hasError('required')">
       ID proof number is required!
    </mat-error>
   </mat-form-field>

Example in first field if I choose option as Adhaar number then in second field the validation must be only number with 12 digit characters max length.

If I choose PAN number then only validation will be alphanumeric with 10 characters max length. And accordingly if I can give error message validation as well. How I can achieve that

EDIT added ts formcontrol

this.PGroup = this._formBuilder.group({
      idProof: ['', Validators.required],
      idProofNumber: ['', [Validators.required,Validators.pattern(/^[\w\s] $/)]]
});

CodePudding user response:

Can you provide your ts code? I see you use ngModel combined with formControlName, and I think that it's combined reactive approach with template driven approach. Anyway, here my advice. Use reactive approach in this way, (only suggestion, you could get the idea and implement base on your preference)

// attr declarations
fieldOne = new FormControl('',[]); // initial value and validators inside array
fieldTwo = new FormControl('', []); // initialValue and validators

// ngOnInit
fieldOne.valueChanges.
.pipe(
debounceTime(100),   // dalay after every change to update your validations
distinctUntilChanged(), // only update validators when value change
tap(value => {

// depend on your options you can use switch here
   if(value === 'Adhaar number'){
    this.fieldTwo.setValidators([Validators.required,Validators.maxLength(12)]);
    this.fieldTwo.updateValueAndValidity();
  } else 
 if(value === 'PAN number'){
    this.fieldTwo.setValidators([Validators.required,Validators.maxLength(10)]);
    this.fieldTwo.updateValueAndValidity();
  } else {
this.fieldTwo.setValidators([Validators.required]);
    this.fieldTwo.updateValueAndValidity();
}
})

)
.subscribe()

Update your html base on your possible errors .

Also you can use formGroup with two field instead of separated formControls, and only change subscription from this.fieldOne.valueChanges to this.form.get('fieldOne').valueChanges


Remember to unsubscribe from this subscription. I suggest https://www.npmjs.com/package/@ngneat/until-destroy

CodePudding user response:

I think you could do something like this,

Lets say you have component with the name AppComponent,

import { Component } from '@angular/core';
import { 
  FormBuilder,
  FormGroup,
  FormControl, 
  ValidationErrors, 
  AbstractControl, 
  ValidatorFn 
} from '@angular/forms';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent {
    title = 'stackoverflow-examples';
    panelOpenState = false;
    idproofOptions: string[] = ['Aadhar','PAN'];
    idproofsForm: FormGroup;

    get idproofsFormControl(): FormControl {
      // debugger
      return this.idproofsForm.controls['idproofs'] as FormControl;
    }

    get idproofsInputFormControl(): FormControl {
      // debugger
      return this.idproofsForm.controls['idproofsInput'] as FormControl;
    }

    idproofInputAadharValidation(): ValidatorFn {
      return (control: AbstractControl): ValidationErrors | null => {
        // debugger
        const pattern = new RegExp("^[0-9]{10}$");
        if (pattern.test(control.value)) {
          return null;
        } else {
          return {
            aadharError: 'Aadhar number is not correct'
          };
        }
      };
    }

    idproofInputPANValidation(): ValidatorFn {
      return (control: AbstractControl): ValidationErrors | null => {
        // debugger
        const pattern = new RegExp("^[a-zA-Z0-9] $");
        if (pattern.test(control.value)) {
          return null;
        } else {
          return {
            panError: 'PAN number is not correct'
          };
        }
      };
    }

    constructor(
      private fb: FormBuilder
    ) { 
      this.idproofsForm = new FormGroup(
        {
          idproofs: new FormControl(''),
          idproofsInput: new FormControl('')
        }
      );
    }

    ngOnInit() {
      this.idproofsForm.valueChanges.subscribe(
        field => {
          // debugger
          console.log(this.idproofsForm.controls['idproofsInput']);
          if (field['idproofs'] && field['idproofs'] === 'PAN') {
            this.idproofsInputFormControl.clearValidators();
            this.idproofsInputFormControl.setValidators(this.idproofInputPANValidation());
          } else if (field['idproofs'] && field['idproofs'] === 'Aadhar') {
            this.idproofsInputFormControl.clearValidators();
            this.idproofsInputFormControl.setValidators(this.idproofInputAadharValidation());
          }
          // debugger
        }
      );
    }

}

Your HTML can look like this,

<label>ID proof<span >*</span></label>
<mat-form-field appearance="outline">
  <mat-select [formControl]="idproofsFormControl" name="idproofs" placeholder="IDProof name" required >
    <mat-option  *ngFor="let idproof of idproofOptions" [value]="idproof">
      {{idproof}}
    </mat-option> 
  </mat-select>
</mat-form-field>
<br/>
<!-- {{idproofsInputFormControl|json}} -->
<label>ID proof number<span >*</span></label>
<mat-form-field appearance="outline">
  <input matInput placeholder="ID Proof Number" required [formControl]="idproofsInputFormControl" >
  <mat-error *ngIf="idproofsInputFormControl.errors">
      {{idproofsInputFormControl.errors['aadharError']}}
  </mat-error>
</mat-form-field>

look at the error below in screenshot enter image description here

Note: My suggestion is that you don't use ngModel the reactive approach is far better, you may have to change this code a little to fit your requirement but I am sure it should be helpful

  • Related