While saving all my grid rows, I need to check whether there is a duplicate for a specific column field
(this.formGroups.get('items') as FormArray).controls.forEach((item) => {
console.log(item.value.attributeDisplayName);
});
I need to stop the form from submission by showing an alert or something similar when there is a duplicate value for attributeDisplayName
. How can I check that in the current forEach loop. Thanks
CodePudding user response:
Instead of checking it while submitting, just check it while filling form only and show the error immediately if user has filled duplicate value.
use this function to check duplicacy -
checkDuplicacy(event, index) {
let length = this.formGroups.value.items.length
let count = 0;
let controls = (<FormArray>this.formGroups.controls.items).controls;
for (let i = 0; i < length; i ) {
if (this.formGroups.value.items[i].attributeDisplayName.toLowerCase() == event.target.value.toLowerCase()) {
count
}
if (count > 1) {
controls[index].get('attributeDisplayName').markAsTouched();
controls[index].get('attributeDisplayName').setValidators(f => <any>{ duplicateName: true })
controls[index].get('attributeDisplayName').updateValueAndValidity()
}
else {
controls[index].get('attributeDisplayName').clearValidators();
controls[index].get('attributeDisplayName').setValidators([Validators.required]);
controls[index].get('attributeDisplayName').updateValueAndValidity();
}
}
}
And call this function in HTML on input blur, and show the error in HTML if duplicate field is found -
<div class="form-control">
<input formControlName="attributeDisplayName" (blur)="checkDuplicacy($event, index)"/>
<span *ngIf="formGroups.controls['items'].controls[index].get('attributeDisplayName').errors?.duplicateName" class="error">
Duplicate field.</span>
</div>
CodePudding user response:
Of course you can use a validator to check the duplicates. The validator is like
validateUniq(index) {
return (control: AbstractControl) => {
if (control.value) {
//search the "formArray"
const formArray = control.parent
? (control.parent.parent as FormArray)
: null;
if (formArray) {
//we create an array with the attributeDisplayNames
const attributes = formArray.value.map((x) => x.attributeDisplayName);
//only give error if there're duplicate before our
//control
return attributes.indexOf(control.value)>=0 &&
attributes.indexOf(control.value)<index
? { duplicateName: true }
: null;
}
}
};
}
You create the formGroup like -see how you pass the "index"
initFormField() {
const index = this.items ? this.items.length : 0;
return this.fb.group({
attributeDisplayName: [
'',
[Validators.required, this.validateUniq(index)],
],
});
}
The problem when we use a Validator over a control is that only is checked when the control changes, so we need make a function checkDuplicacy like @Shyam say -but in this case is more simple:
checkDuplicacy(index) {
this.items.controls.forEach((x,i)=>{
if (index!=i)
(x as FormGroup).get('attributeDisplayName').updateValueAndValidity()
})
}
The last piece to completate the jigsaw is a function to get the control
getAtributeDisplayNameAt(index: number) {
return this.items
? (this.items.at(index).get('attributeDisplayName') as FormControl)
: null;
}
And an html like
<form [formGroup]="formGroups" novalidate autocomplete="off">
<div formArrayName="items">
<div
*ngFor="let item of items.controls; let index = index"
[formGroupName]="index"
>
<div class="form-control">
<input
placeholder="Enter here"
formControlName="attributeDisplayName"
(input)="checkDuplicacy(index)"
/>
<span
*ngIf="getAtributeDisplayNameAt(index)?.errors?.duplicateName"
class="error"
>
Duplicate field.</span
>
</div>
</div>
</div>
<button (click)="addFormField()">Add More</button>
</form>
See how we call to the function checkDuplicacy
in the event input
-you can subscribe also to the valueChange of the control
The stackblitz