【问题标题】:Check if there is a duplicate item in FormGroups field in Angular reactive form检查Angular反应形式的FormGroups字段中是否存在重复项
【发布时间】:2021-11-17 15:49:56
【问题描述】:

在保存所有网格行时,我需要检查特定列字段是否存在重复项

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

attributeDisplayName 存在重复值时,我需要通过显示警报或类似内容来阻止表单提交。如何在当前的 forEach 循环中检查它。谢谢

我在我的 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)">
          
          <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>

下面是 .ts 文件中的 FormGroup 声明

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

我使用此 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++;
      }      
    }

【问题讨论】:

    标签: javascript angular foreach


    【解决方案1】:

    不要在提交时检查它,而只是在填写表单时检查它,如果用户填写了重复值,则立即显示错误。

    Working demo here.

    使用此功能检查重复性 -

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

    并更新了 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>
    

    【讨论】:

    • 感谢您的回复。我正在使用响应式表单,所以我们可以像验证器一样编写它并在字段的表单组声明中使用它,而不是使用它 onblur()?请建议
    • @vamsi 我认为这是不可能的(不确定),因为为了在自定义验证器函数中使用相同的逻辑,我们需要访问验证器函数中的整个 formGroup 以获取项目值。并且整个 formGroup 不能传入验证器,因为我们在声明 formGroup 时没有它。
    • @ShyamJoshi,您可以在 vaidator 中使用 control.parent.parent 访问 FormArray,请参阅我的回答
    • @Eliseo 哦,那真是太好了。谢谢。支持您的答案...
    • @ShyamJoshi,我已经更新了我的问题以便更好地理解。我实际上没有在我的 HTML 标记中使用
      标记,也没有使用任何“索引”。因此,当我尝试使用此代码时,不知不觉地,我在“索引”处收到错误,说它是未定义的。我可以为此做任何解决方法吗?请提出建议。
    【解决方案2】:

    当然,您可以使用验证器来检查重复项。验证器就像

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

    你创建 formGroup 就像 - 看看你如何传递“索引”

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

    我们在控件上使用 Validator 时的问题是,只有在控件更改时才检查,所以我们需要像 @Shyam 说的那样创建一个函数 checkDuplicacy - 但在这种情况下更简单:

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

    完成拼图的最后一块是获取控制权的函数

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

    还有一个类似的html

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

    看看我们如何在input事件中调用函数checkDuplicacy——你也可以订阅控件的valueChange

    stackblitz

    【讨论】:

      猜你喜欢
      • 2018-10-28
      • 2018-11-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多