admin管理员组文章数量:1291392
I have several form arrays and I need a validation so that a particular field in each form row has to be unique across all the form arrays. If any of the values appear more than once, both form fields have to be marked in red.
I managed to write a function so that if there are any changes to those fields, the function returns true/false. But I'm unsure how to use this for the actual validation process.
ponent.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 autoplete = "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 autoplete = "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 autoplete = "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 autoplete = "off" matInput placeholder="Description" formControlName="description">
</mat-form-field>
</div>
</div>
</div>
ponent.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;
}
For every keystroke, this function is called and a check is done against all the values in all other form arrays to see if there are any duplicates. But how do I change it so that I can use this function as a validator and mark the duplicate input fields accordingly?
I have several form arrays and I need a validation so that a particular field in each form row has to be unique across all the form arrays. If any of the values appear more than once, both form fields have to be marked in red.
I managed to write a function so that if there are any changes to those fields, the function returns true/false. But I'm unsure how to use this for the actual validation process.
ponent.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 autoplete = "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 autoplete = "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 autoplete = "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 autoplete = "off" matInput placeholder="Description" formControlName="description">
</mat-form-field>
</div>
</div>
</div>
ponent.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;
}
For every keystroke, this function is called and a check is done against all the values in all other form arrays to see if there are any duplicates. But how do I change it so that I can use this function as a validator and mark the duplicate input fields accordingly?
Share Improve this question asked Oct 27, 2019 at 6:41 InceptionInception 4651 gold badge11 silver badges32 bronze badges2 Answers
Reset to default 6You has two aproach when use validations
1.-Validate the control and in (input) call to updateValueAndValidity of the rest of the controls. This is because when you make a validation over a control only validate this control.
You can use a function like
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;
};
}
And another to updateValueAndValidity the other controls
updateValidation(arrayName,field)
{
(this.form.get(arrayName) as FormArray).controls.forEach(
group=>group.get(field).updateValueAndValidity()
)
}
The .html bees like
<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>
And you create the form like
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")
)
})
)
)
});
The other aproach is make a custom validator over the 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;
};
}
The formArray you create like
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")
)
});
The problem with this aproach is that is the FormArray who has the error. If only has a input normal, we can use some like
<div *ngIf="form.get('temperatureFormArray').errors?.error.indexOf(i)>=0">
duplicate
</div>
But we are using material input, so we need change when you mark a control as invalid. For this we need use a custom ErrorStateMatcher. This is only a function that make mat-error show if the function return true. We need pass as argument the formArrayName and the index, so we has defined some like
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));
}
}
And a funciton in our ponent like
matcher(formArrayName,index)
{
return new DuplicateStateMatcher(formArrayName,index);
}
The .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>
You can see the two aproach in stackblitz
Angular forms can have custom validators. Essentially, a function that performs logic to decide if the field is valid or not. Here's a how to guide. Use the same logic you have in the testFunction and apply it the the custom validator. One built, apply it to all the fields in the arrays.
本文标签: javascriptValidation to prevent duplicate form values in angular formsStack Overflow
版权声明:本文标题:javascript - Validation to prevent duplicate form values in angular forms - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1741528914a2383635.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论