如何为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
相关产品推荐
相关产品推荐

