Home > other >  Check if there is a duplicate item in FormGroups field in Angular reactive form
Check if there is a duplicate item in FormGroups field in Angular reactive form

Time:11-18

While saving all my grid rows, I need to check whether there is a duplicate for a specific column field

 (this.formGroups.get('items') as FormArray).controls.forEach((item) => {
    console.log(item.value.attributeDisplayName);       
  });

I need to stop the form from submission by showing an alert or something similar when there is a duplicate value for attributeDisplayName. How can I check that in the current forEach loop. Thanks

CodePudding user response:

Instead of checking it while submitting, just check it while filling form only and show the error immediately if user has filled duplicate value.

Working demo here.

use this function to check duplicacy -

checkDuplicacy(event, index) {
    let length = this.formGroups.value.items.length
    let count = 0;
    let controls = (<FormArray>this.formGroups.controls.items).controls;
    for (let i = 0; i < length; i  ) {
      if (this.formGroups.value.items[i].attributeDisplayName.toLowerCase() == event.target.value.toLowerCase()) {
        count  
      }
      if (count > 1) {
        controls[index].get('attributeDisplayName').markAsTouched();
        controls[index].get('attributeDisplayName').setValidators(f => <any>{ duplicateName: true })
        controls[index].get('attributeDisplayName').updateValueAndValidity()
      }
      else {
        controls[index].get('attributeDisplayName').clearValidators();
        controls[index].get('attributeDisplayName').setValidators([Validators.required]);
        controls[index].get('attributeDisplayName').updateValueAndValidity();
      }
    }
  }

And call this function in HTML on input blur, and show the error in HTML if duplicate field is found -

     <div class="form-control">
       <input formControlName="attributeDisplayName" (blur)="checkDuplicacy($event, index)"/>
 <span *ngIf="formGroups.controls['items'].controls[index].get('attributeDisplayName').errors?.duplicateName" class="error">
  Duplicate field.</span>
  </div>

CodePudding user response:

Of course you can use a validator to check the duplicates. The validator is like

  validateUniq(index) {
    return (control: AbstractControl) => {
      if (control.value) {

        //search the "formArray"
        const formArray = control.parent
          ? (control.parent.parent as FormArray)
          : null;

        if (formArray) {
          //we create an array with the attributeDisplayNames
          const attributes = formArray.value.map((x) => x.attributeDisplayName);
      
          //only give error if there're duplicate before our
          //control
      
          return attributes.indexOf(control.value)>=0 && 
                 attributes.indexOf(control.value)<index
            ? { duplicateName: true }
            : null;
        }
      }
    };
  }

You create the formGroup like -see how you pass the "index"

  initFormField() {
    const index = this.items ? this.items.length : 0;
    return this.fb.group({
      attributeDisplayName: [
        '',
        [Validators.required, this.validateUniq(index)],
      ],
    });
  }

The problem when we use a Validator over a control is that only is checked when the control changes, so we need make a function checkDuplicacy like @Shyam say -but in this case is more simple:

  checkDuplicacy(index) {
    this.items.controls.forEach((x,i)=>{
      if (index!=i)
        (x as FormGroup).get('attributeDisplayName').updateValueAndValidity()
    })
  }

The last piece to completate the jigsaw is a function to get the control

  getAtributeDisplayNameAt(index: number) {
    return this.items
      ? (this.items.at(index).get('attributeDisplayName') as FormControl)
      : null;
  }

And an html like

<form [formGroup]="formGroups" novalidate autocomplete="off">
  <div formArrayName="items">
    <div
      *ngFor="let item of items.controls; let index = index"
      [formGroupName]="index"
    >
      <div class="form-control">
        <input
          placeholder="Enter here"
          formControlName="attributeDisplayName" 
          (input)="checkDuplicacy(index)"
        />
        <span
          *ngIf="getAtributeDisplayNameAt(index)?.errors?.duplicateName"
          class="error"
        >
          Duplicate field.</span
        >
      </div>
    </div>
  </div>
  <button (click)="addFormField()">Add More</button>
</form>

See how we call to the function checkDuplicacy in the event input -you can subscribe also to the valueChange of the control

The stackblitz

  • Related