我有几个表单数组,我需要进行验证,以便每个表单行中的特定字段在所有表单数组中都是唯一的。如果任何值出现多次,则两个表单字段都必须用红色标记。
我设法编写了一个函数,这样如果这些字段有任何更改,函数就会返回true/false。但我不确定如何将其用于实际的验证过程。
component.html:
<div formArrayName="temperatureFormArr">
<div class="row" *ngFor="let temperature of parentForm['controls'].detailForm['controls'].temperatureFormArr['controls']; let i=index"
[formGroupName]="i">
<div class="col-4">
<mat-form-field appearance="outline" class="fex-input">
<mat-label>Higher Level Function</mat-label>
<input autocomplete = "off" matInput placeholder="Higher Level Function" (input)="testFunction(i, 'temperatureFormArr')" formControlName="higherLevelFunction">
</mat-form-field>
</div>
<div class="col-6">
<mat-form-field appearance="outline" class="fex-input">
<mat-label>Description</mat-label>
<input autocomplete = "off" matInput placeholder="Description" formControlName="description">
</mat-form-field>
</div>
</div>
</div>
<div formArrayName="waterPressureFormArr">
<div class="row" *ngFor="let waterPressure of parentForm['controls'].detailForm['controls'].waterPressureFormArr['controls']; let i=index"
[formGroupName]="i">
<div class="col-4">
<mat-form-field appearance="outline" class="fex-input">
<mat-label>Higher Level Function</mat-label>
<input autocomplete = "off" matInput placeholder="Higher Level Function" (input)="testFunction(i, 'waterPressureFormArr')" formControlName="higherLevelFunction">
</mat-form-field>
</div>
<div class="col-6">
<mat-form-field appearance="outline" class="fex-input">
<mat-label>Description</mat-label>
<input autocomplete = "off" matInput placeholder="Description" formControlName="description">
</mat-form-field>
</div>
</div>
</div>
组件.ts
testFunction(i: any, typeOfArray: string) {
var duplicateFlag = false;
var testValue = this.parentForm['controls'].detailForm['controls'][typeOfArray].controls[i].value;
for (let index = 0; index < this.parentForm['controls'].detailForm['controls'].temperatureFormArr.length; index++) {
if(this.parentForm['controls'].detailForm['controls'].temperatureFormArr['controls'][index]
.get('higherLevelFunction').value == testValue.higherLevelFunction && (index != i || typeOfArray != 'temperatureFormArr')) {
duplicateFlag = true;
}
}
for (let index = 0; index < this.parentForm['controls'].detailForm['controls'].waterPressureFormArr.length; index++) {
if(this.parentForm['controls'].detailForm['controls'].waterPressureFormArr['controls'][index]
.get('higherLevelFunction').value == testValue.higherLevelFunction && (index != i || typeOfArray != 'waterPressureFormArr')) {
duplicateFlag = true;
}
}
return duplicateFlag;
}
对于每一次击键,都会调用此函数,并对所有其他表单数组中的所有值进行检查,以查看是否存在重复值。但是,我该如何更改它,以便将此函数用作验证器,并相应地标记重复的输入字段?
使用验证时有两个选项
1.-验证控件,并在(input(调用中更新其余控件的值和有效性。这是因为当您对控件进行验证时,只验证该控件。
你可以使用类似的功能
duplicateControlError(field) {
return (control: FormControl) => {
let result: boolean = false;
const group = control.parent as FormGroup;
if (group) {
const values = control.parent.parent.value.map(x => x[field]);
result = values.filter(x => x == control.value).length > 1;
}
return result ? { error: "duplicate" } : null;
};
}
另一个更新值和有效性另一个控制
updateValidation(arrayName,field)
{
(this.form.get(arrayName) as FormArray).controls.forEach(
group=>group.get(field).updateValueAndValidity()
)
}
html变得像
<mat-form-field class="example-full-width">
<input matInput placeholder="higherLevelFunction" formControlName="higherLevelFunction" (input)="updateValidation('temperatureFormArray','higherLevelFunction')">
<mat-error>Duplicate</mat-error>
</mat-form-field>
然后创建类似的表单
form = new FormGroup({
temperatureFormArray: new FormArray(
this.data.map(
(x, index) =>
new FormGroup({
description: new FormControl(x.description),
higherLevelFunction: new FormControl(
x.higherLevelFunction,
this.duplicateControlError("higherLevelFunction")
)
})
)
)
});
另一种方法是在FormArray 上制作一个自定义验证器
duplicateError(field) {
return (formArray: FormArray) => {
let duplicate = [];
formArray.value.forEach((x, index) => {
if (formArray.value.filter(y => y[field] == x[field]).length > 1)
duplicate.push(index);
});
return duplicate.length ? { error: duplicate } : null;
};
}
您创建的formArray类似
form = new FormGroup({
temperatureFormArray: new FormArray(
this.data.map(
(x, index) =>
new FormGroup({
description: new FormControl(x.description),
higherLevelFunction: new FormControl(
x.higherLevelFunction)
)
})
),
this.duplicateError("higherLevelFunction")
)
});
这个方法的问题是FormArray有错误。如果只有一个正常的输入,我们可以使用一些像
<div *ngIf="form.get('temperatureFormArray').errors?.error.indexOf(i)>=0">
duplicate
</div>
但我们使用的是材料输入,所以当您将控件标记为无效时,我们需要进行更改。为此,我们需要使用自定义的ErrorStateMatcher。如果函数返回true,这只是一个使mat error显示的函数。我们需要传递formArrayName和索引作为参数,所以我们定义了一些类似的
export class DuplicateStateMatcher implements ErrorStateMatcher {
constructor(private formArrayName:string,private index:number){}
isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
const formArray=form.form.get(this.formArrayName) as FormArray
const error=formArray && formArray.errors?
formArray.errors.error.indexOf(this.index)>=0:null
return (control && error && (control.dirty || control.touched));
}
}
我们组件中的一个功能,如
matcher(formArrayName,index)
{
return new DuplicateStateMatcher(formArrayName,index);
}
.html
<mat-form-field class="example-full-width">
<input matInput placeholder="higherLevelFunction" formControlName="higherLevelFunction" [errorStateMatcher]="matcher('temperatureFormArray',i)">
<mat-error>Duplicate</mat-error>
</mat-form-field>
你可以在stackblitz 中看到这两个
角度表单可以有自定义验证器。本质上,一种执行逻辑以决定字段是否有效的函数。这里有一个指南。使用与testFunction中相同的逻辑,并将其应用于自定义验证器。生成一个,将其应用于数组中的所有字段。