У вас есть два подхода при использовании проверок
1.-Подтвердите вызов элемента управления и вход (вход) для updateValueAndValidity остальных элементов управления. Это связано с тем, что при проверке элемента управления выполняется только проверка этого элемента управления.
Вы можете использовать функцию типа
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;
};
}
и другую для updateValueAndValidity других элементов управления
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. Это только функция, которая заставляет mat-error показывать, если функция возвращает true. Нам нужно передать в качестве аргумента 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