2

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

I am using kendo angular components in my HTML markup and I am not using form tag. Below is an example for column declaration

  <kendo-grid-column field="attributeDisplayName" title="CUSTOM FIELD LABEL" width="190">  
        <ng-template kendoGridEditTemplate let-column="column" let-formGroup="formGroup" >          
          <input ngDefaultControl  class="k-textbox" [formControl]="formGroup.get(column.field)">
          
          <div *ngIf="formGroup.get(column.field).errors && (formGroup.get(column.field).dirty || formGroup.get(column.field).touched)">
                <span style="color:red" class="k-icon k-i-warning"></span>
                <span style="color:red">CUSTOM FIELD LABEL is a required field</span>
                
          </div>

        </ng-template>
    </kendo-grid-column>

Below is FormGroup declartion in .ts file

    public formGroup: FormGroup;
    public formGroups: FormGroup = new FormGroup({ items: new FormArray([]) });
    
    public createFormGroup = (dataItem) =>
        new FormGroup({
            atrributeId: new FormControl(dataItem.atrributeId),
            objectType: new FormControl(dataItem.objectType, Validators.required),
            attributeDisplayName: new FormControl(dataItem.attributeDisplayName, Validators.required),     
            dataType: new FormControl(dataItem.dataType, Validators.required),
            inputValues: new FormControl(dataItem.inputValues, [Validators.required,  InputValuesValidator]),
            isGridEligible: new FormControl(dataItem.isGridEligible, Validators.required),
            isInvoiceEligible: new FormControl(dataItem.isInvoiceEligible, Validators.required),
        });

An example function where I use this FormGroup

    public editRows(grid) {      
      this.isEdited = true;
      let currentRow = 0;
      let rows: any = grid.data.data;
  
      for (let i = 0; i < rows.length; i++) {
        const formGroup = this.createFormGroup(rows[i]);          
        this.formGroup = formGroup;
        (this.formGroups.get('items') as FormArray).push(formGroup);        
        grid.editRow(currentRow, formGroup, {skipFocus: true});
        currentRow++;
      }      
    }

2 Answers 2

4

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, field: FormControl) {
    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) {
        field.markAsTouched();
        field.setValidators((f) => <any>{ duplicateName: true });
        field.updateValueAndValidity();
      } else {
        field.clearValidators();
        field.setValidators([Validators.required]);
        field.updateValueAndValidity();
      }
    }
  }

And Updated HTML -

    <kendo-grid-column field="attributeDisplayName" title="CUSTOM FIELD LABEL" width="190">  
<ng-template kendoGridEditTemplate let-column="column" let-formGroup="formGroup" >          
  <input ngDefaultControl  class="k-textbox" [formControl]="formGroup.get(column.field)" (blur)="checkDuplicacy($event, formGroup.get(column.field))">
  

      <div *ngIf="formGroup.get(column.field).errors && (formGroup.get(column.field).dirty || formGroup.get(column.field).touched)">
            <span style="color:red" class="k-icon k-i-warning"></span>
            <span style="color:red">CUSTOM FIELD LABEL is a required field</span>
            
      </div>
    
      <span *ngIf="formGroup.get(column.field).errors?.duplicateName" style="color:red">
      Duplicate field.</span>
    
    </ng-template>
    </kendo-grid-column>
Sign up to request clarification or add additional context in comments.

10 Comments

Thanks for the response. I am using reactive form, so can we write this like a validator and use it in the formgroup declaration for the field, instead of using it onblur()? Please suggest
@vamsi I think it's not possible (not sure) because, for using the same logic in the custom validator function, we need to access the entire formGroup inside the validator function for getting items value. And entire formGroup can not be passed in validator because we do not have it at the time of declaring formGroup.
@ShyamJoshi, you can access to the FormArray using control.parent.parent in the vaidator, see my answer
@Eliseo Ohh, that's really nice. Thanks. Upvoting your answer...
@ShyamJoshi, I have updated my question for better understanding. I am actually not using <form> tag in my HTML markup, neither any 'index'. So, obliviously when I try to use this code, I am getting error at 'index', saying it is undefined. Any workaround I can do for this? Please suggest.
|
1

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.