Mientras guardo todas las filas de mi cuadrícula, necesito verificar si hay un duplicado para un campo de columna específico
(this.formGroups.get('items') as FormArray).controls.forEach((item) => { console.log(item.value.attributeDisplayName); }); Necesito detener el envío del formulario mostrando una alerta o algo similar cuando hay un valor duplicado para attributeDisplayName . ¿Cómo puedo verificar eso en el bucle forEach actual? Gracias
Estoy usando componentes angulares de kendo en mi marcado HTML y no estoy usando una etiqueta de formulario. A continuación se muestra un ejemplo de declaración de columna.
<kendo-grid-column field="attributeDisplayName" title="CUSTOM FIELD LABEL" width="190"> <ng-template kendoGridEditTemplate let-column="column" let-formGroup="formGroup" > <input ngDefaultControl class="k-textbox" [formControl]="formGroup.get(column.field)"> <div *ngIf="formGroup.get(column.field).errors && (formGroup.get(column.field).dirty || formGroup.get(column.field).touched)"> <span style="color:red" class="k-icon ki-warning"></span> <span style="color:red">CUSTOM FIELD LABEL is a required field</span> </div> </ng-template> </kendo-grid-column>A continuación se muestra la declaración de FormGroup en el archivo .ts
public formGroup: FormGroup; public formGroups: FormGroup = new FormGroup({ items: new FormArray([]) }); public createFormGroup = (dataItem) => new FormGroup({ atrributeId: new FormControl(dataItem.atrributeId), objectType: new FormControl(dataItem.objectType, Validators.required), attributeDisplayName: new FormControl(dataItem.attributeDisplayName, Validators.required), dataType: new FormControl(dataItem.dataType, Validators.required), inputValues: new FormControl(dataItem.inputValues, [Validators.required, InputValuesValidator]), isGridEligible: new FormControl(dataItem.isGridEligible, Validators.required), isInvoiceEligible: new FormControl(dataItem.isInvoiceEligible, Validators.required), });Una función de ejemplo donde uso este FormGroup
public editRows(grid) { this.isEdited = true; let currentRow = 0; let rows: any = grid.data.data; for (let i = 0; i < rows.length; i++) { const formGroup = this.createFormGroup(rows[i]); this.formGroup = formGroup; (this.formGroups.get('items') as FormArray).push(formGroup); grid.editRow(currentRow, formGroup, {skipFocus: true}); currentRow++; } }En lugar de verificarlo mientras lo envía, solo verifíquelo mientras completa el formulario y muestre el error inmediatamente si el usuario ha completado un valor duplicado.
use esta función para verificar la duplicación -
checkDuplicacy(event, field: FormControl) { 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) { field.markAsTouched(); field.setValidators((f) => <any>{ duplicateName: true }); field.updateValueAndValidity(); } else { field.clearValidators(); field.setValidators([Validators.required]); field.updateValueAndValidity(); } } }Y HTML actualizado -
<kendo-grid-column field="attributeDisplayName" title="CUSTOM FIELD LABEL" width="190"> <ng-template kendoGridEditTemplate let-column="column" let-formGroup="formGroup" > <input ngDefaultControl class="k-textbox" [formControl]="formGroup.get(column.field)" (blur)="checkDuplicacy($event, formGroup.get(column.field))"> <div *ngIf="formGroup.get(column.field).errors && (formGroup.get(column.field).dirty || formGroup.get(column.field).touched)"> <span style="color:red" class="k-icon ki-warning"></span> <span style="color:red">CUSTOM FIELD LABEL is a required field</span> </div> <span *ngIf="formGroup.get(column.field).errors?.duplicateName" style="color:red"> Duplicate field.</span> </ng-template> </kendo-grid-column>Por supuesto, puede usar un validador para verificar los duplicados. El validador es como
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; } } }; }Creas el formGroup como -mira cómo pasas el "índice"
initFormField() { const index = this.items ? this.items.length : 0; return this.fb.group({ attributeDisplayName: [ '', [Validators.required, this.validateUniq(index)], ], }); }El problema cuando usamos un validador sobre un control es que solo se verifica cuando cambia el control, por lo que necesitamos hacer una función de verificación de duplicados como dice @Shyam, pero en este caso es más simple:
checkDuplicacy(index) { this.items.controls.forEach((x,i)=>{ if (index!=i) (x as FormGroup).get('attributeDisplayName').updateValueAndValidity() }) }La última pieza para completar el rompecabezas es una función para obtener el control.
getAtributeDisplayNameAt(index: number) { return this.items ? (this.items.at(index).get('attributeDisplayName') as FormControl) : null; }Y un html como
<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> Vea cómo llamamos a la función checkDuplicacy en la input del evento; también puede suscribirse al valueChange del control
el bombardeo