You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为FormArray中FormGroup的label字段添加唯一性校验?

实现FormArray中label字段的唯一性校验

要给FormArray内所有FormGroup的label字段做唯一性校验,并且为重复字段单独标记错误,需要从数组级校验和控件错误同步两方面入手,具体实现如下:

1. 编写数组级别的唯一性校验器

单个控件的校验器无法获取整个FormArray的所有值,因此我们需要给fields这个FormArray绑定一个全局校验器,用于遍历所有label值、识别重复项,并给对应控件设置错误:

import { AbstractControl, FormArray, ValidationErrors, ValidatorFn } from '@angular/forms';

// 数组级唯一性校验器
function uniqueLabelsArrayValidator(): ValidatorFn {
  return (control: AbstractControl): ValidationErrors | null => {
    const formArray = control as FormArray;
    // 提取所有label控件及其非空值
    const labelControls = formArray.controls.map(group => group.get('label'));
    const validLabelValues = labelControls
      .map(ctrl => ctrl?.value.trim())
      .filter(value => value); // 过滤空值,避免和required校验冲突

    // 找出重复的label值
    const seenValues = new Set<string>();
    const duplicateValues = new Set<string>();
    validLabelValues.forEach(value => {
      seenValues.has(value) ? duplicateValues.add(value) : seenValues.add(value);
    });

    // 给重复的控件标记错误,非重复控件清除重复错误
    labelControls.forEach(ctrl => {
      const currentValue = ctrl?.value.trim();
      if (currentValue && duplicateValues.has(currentValue)) {
        // 保留原有错误(比如required),新增duplicate错误
        ctrl.setErrors({ ...ctrl.errors, duplicate: true });
      } else if (ctrl?.errors?.duplicate) {
        // 移除duplicate错误,保留其他错误
        const { duplicate, ...remainingErrors } = ctrl.errors;
        ctrl.setErrors(Object.keys(remainingErrors).length ? remainingErrors : null);
      }
    });

    // 返回数组级错误(可选,用于标记整个数组的状态)
    return duplicateValues.size > 0 ? { duplicateLabels: true } : null;
  };
}

2. 绑定校验器到FormArray

修改表单初始化代码,将上述校验器绑定到fields数组上:

form: FormGroup = this.formBuilder.group({
  // 给FormArray添加全局校验器
  fields: this.formBuilder.array([], [uniqueLabelsArrayValidator()]),
});

private createField() {
  const fieldGroup = this.formBuilder.group({
    label: ['', [Validators.required]],
  });

  // 监听单个label的变化,触发整个数组的校验
  fieldGroup.get('label')?.valueChanges.subscribe(() => {
    // 禁用emitEvent避免循环触发valueChanges
    (this.form.get('fields') as FormArray).updateValueAndValidity({ emitEvent: false });
  });

  return fieldGroup;
}

public addField() {
  (this.form.get('fields') as FormArray).push(this.createField());
}

3. 模板中显示错误

在模板里针对每个label控件,判断并显示duplicate错误:

<div [formGroup]="form">
  <div formArrayName="fields">
    <div *ngFor="let field of fields.controls; let i = index" [formGroup]="field">
      <input formControlName="label" placeholder="输入标签">
      <!-- 显示必填错误 -->
      <span *ngIf="field.get('label')?.hasError('required')">标签不能为空</span>
      <!-- 显示重复错误 -->
      <span *ngIf="field.get('label')?.hasError('duplicate')">该标签已存在</span>
    </div>
  </div>
  <button (click)="addField()">添加标签</button>
</div>

关键说明

  • 数组级校验器可以访问所有控件的值,确保能准确识别重复项;
  • 给每个label控件绑定valueChanges,确保修改任意一个label时,都会触发整个数组的校验,同步更新所有控件的错误状态;
  • 保留原有required校验,唯一性校验仅针对非空值生效。

内容的提问来源于stack exchange,提问作者aaadraniki

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 22:53:31