Edición y validación de cuadrícula Angular

    La edición de Grid expone un mecanismo de validación incorporado de la entrada del usuario al editar celdas/filas. Amplía la funcionalidad de validación Angular Form para permitir una integración más sencilla con una funcionalidad conocida. Cuando cambia el estado del editor, se aplican indicadores visuales a la celda editada.

    Configuración

    Configure via template-driven configuration

    Ampliamos algunas de las directivas del validador Angular Forms para trabajar directamente con IgxColumn. Los mismos validadores están disponibles como atributos que se establecerán de forma declarativa en igx-column. Los siguientes validadores son compatibles desde el primer momento:

    • requerido
    • mín.
    • máximo
    • correo electrónico
    • longitud mínima
    • longitud máxima
    • patrón

    Para validar que se establecerá una entrada de columna y que el valor se formateará como un correo electrónico, puede utilizar las directivas relacionadas:

    <igx-column [field]="email" [header]="User E-mail" required email></igx-column>
    

    El siguiente ejemplo demuestra cómo utilizar las directivas de validador required, email y min prediseñadas en un Grid.

    Configure via reactive forms

    Exponemos el FormGroup que se utilizará para la validación cuando comience la edición en una fila/celda a través de un evento formGroupCreated. Puedes modificarlo agregando tus propios validadores para los campos relacionados:

    <igx-grid (formGroupCreated)='formCreateHandler($event)' ...>
    
        public formCreateHandler(args: IGridFormGroupCreatedEventArgs) {
            const formGroup = args.formGroup;
            const orderDateRecord = formGroup.get('OrderDate');
            const requiredDateRecord = formGroup.get('RequiredDate');
            const shippedDateRecord = formGroup.get('ShippedDate');
    
            orderDateRecord.addValidators(this.futureDateValidator());
            requiredDateRecord.addValidators(this.pastDateValidator());
            shippedDateRecord.addValidators(this.pastDateValidator());
        }
    

    Puede decidir escribir su propia función de validación o utilizar una de las funciones de validación Angular integradas.

    Validation service API

    La cuadrícula expone un servicio de validación a través de la propiedad validation. Ese servicio tiene las siguientes API públicas:

    • valid: devuelve si el estado de validación de la cuadrícula es válido.
    • getInvalid: devuelve registros con estados no válidos.
    • clear: borra el estado para el registro por identificación o borra todos los estados si no se proporciona ninguna identificación.
    • markAsTouched: marca el registro/campo relacionado como tocado.

    Los estados no válidos persistirán hasta que los errores de validación en ellos se corrijan de acuerdo con la regla de validación o se eliminen.

    Validation triggers

    La validación se activará en los siguientes escenarios:

    • Mientras se edita a través del editor de celdas según el validationTrigger de la cuadrícula. Ya sea al change mientras se escribe en el editor, o al blur cuando el editor pierde el foco o se cierra.
    • Al actualizar celdas/filas a través de la API: updateRow, updateCell, etc.
    • Cuando se utiliza la edición por lotes y la API undo / redo del servicio de transacciones.

    Nota: La validación no se activará para los registros que no se hayan editado mediante la entrada del usuario o mediante la API de edición. Los indicadores visuales en la celda solo se mostrarán si la entrada relacionada se considera tocada, ya sea mediante la interacción del usuario o mediante la API markAsTouched del servicio de validación.

    Angular Grid Validation Customization Options

    Set a custom validator

    Puede definir su propia directiva de validación para usar en una <igx-column> en la plantilla.

    @Directive({
        selector: '[phoneFormat]',
        providers: [{ provide: NG_VALIDATORS, useExisting: PhoneFormatDirective, multi: true }]
    })
    export class PhoneFormatDirective extends Validators {
        @Input('phoneFormat')
        public phoneFormatString = '';
    
        public validate(control: AbstractControl): ValidationErrors | null {
            return this.phoneFormatString ? phoneFormatValidator(new RegExp(this.phoneFormatString, 'i'))(control)
                : null;
        }
    }
    

    Una vez que esté definido y agregado en el módulo de su aplicación, puede configurarlo de forma declarativa en una columna determinada en la cuadrícula:

    <igx-column phoneFormat="\+\d{1}\-(?!0)(\d{3})\-(\d{3})\-(\d{4})\b" ...>
    

    Change default error template

    Puede definir su propia plantilla de error personalizada que se mostrará en la información sobre herramientas de error cuando la celda entre en un estado no válido. Esto es útil en escenarios en los que desea agregar su propio mensaje de error personalizado o cambiar la apariencia o el contenido del mensaje.

    <igx-column ... >
      <ng-template igxCellValidationError let-cell='cell' let-defaultErr="defaultErrorTemplate">
          <ng-container *ngTemplateOutlet="defaultErr">
          </ng-container>
          <div *ngIf="cell.validation.errors?.['phoneFormat']">
            Please enter correct phone format
          </div>
      </ng-template>
    </igx-column>
    

    Prevent exiting edit mode on invalid state

    En algunos casos, es posible que desee impedir el envío de un valor no válido en los datos. En esos escenarios, puede usar los eventos cellEdit o rowEdit y cancelar el evento en caso de que el nuevo valor no sea válido. Los argumentos de ambos eventos tienen una propiedad valid y pueden cancelarse en consecuencia. Cómo se utiliza se puede ver en el ejemplo de Validación entre campos.

    <igx-grid (cellEdit)='cellEdit($event)' ...>
    
    public cellEdit(evt) {
      if (!evt.valid) {
        evt.cancel = true;
      }
    }
    

    Example

    El siguiente ejemplo demuestra las opciones de personalización mencionadas anteriormente.

    Cross-field validation

    En algunos escenarios, la validación de un campo puede depender del valor de otro campo en el registro. En ese caso, se puede utilizar un validador personalizado para comparar los valores en el registro a través de su FormGroup compartido.

    El siguiente ejemplo demuestra una validación entre campos entre diferentes campos del mismo registro. Comprueba la validez de las fechas en comparación con la fecha actual y entre la fecha activa y la de creación del registro, así como la proporción de transacciones ganadas/perdidas para cada empleado. Todos los errores se recopilan en una columna fijada separada que muestra que el registro no es válido y muestra los errores relacionados.

    Las siguientes líneas de código muestran la función de validación de campos cruzados, que contiene las comparaciones y establece los errores relacionados con ellas.

    private rowValidator(): ValidatorFn {
        return (formGroup: FormGroup): ValidationErrors | null => {
            let returnObject = {};
            const createdOnRecord = formGroup.get('created_on');
            const lastActiveRecord = formGroup.get('last_activity');
            const winControl = formGroup.get('deals_won');
            const loseControl = formGroup.get('deals_lost');
            const actualSalesControl = formGroup.get('actual_sales');
    
            // Validate dates
            const curDate = new Date();
            if (new Date(createdOnRecord.value) > curDate) {
                // The created on date shouldn't be greater than current date.
                returnObject['createdInvalid'] =  true;
            }
            if (new Date(lastActiveRecord.value) > curDate) {
                // The last active date shouldn't be greater than current date.
                returnObject['lastActiveInvalid'] = true;
            }
            if (new Date(createdOnRecord.value) > new Date(lastActiveRecord.value)) {
                // The created on date shouldn't be greater than last active date.
                returnObject['createdLastActiveInvalid'] = true;
            }
            
            // Validate deals
            const dealsRatio = this.calculateDealsRatio(winControl.value, loseControl.value);
            if (actualSalesControl.value === 0 && dealsRatio > 0) {
                // If the actual sales value is 0 but there are deals made.
                returnObject['salesZero'] = true;
            }
            if (actualSalesControl.value > 0 && dealsRatio === 0) {
                // If the deals ratio based on deals won is 0 but the actual sales is bigger than 0.
                returnObject['salesNotZero'] = true;
            }
            
            return returnObject;
        };
    }
    
    public calculateDealsRatio(dealsWon, dealsLost) {
        if (dealsLost === 0) return dealsWon + 1;
        return Math.round(dealsWon / dealsLost * 100) / 100;
    }
    

    El validador de campos cruzados se puede agregar al formGroup de la fila del evento formGroupCreated, que devuelve el nuevo formGroup para cada fila al ingresar al modo de edición:

    <igx-grid #grid1 [data]="transactionData" [width]="'100%'" [height]="'480px'" [autoGenerate]="false" 
            [batchEditing]="true" [rowEditable]="true" [primaryKey]="'id'"
            (formGroupCreated)='formCreateHandler($event)'>
        <!-- ... -->
    </igx-grid>
    
    
    public formCreateHandler(evt: IGridFormGroupCreatedEventArgs) {
        evt.formGroup.addValidators(this.rowValidator());
    }
    

    Los diferentes errores se muestran en una celda con plantilla que combina todos los errores en una única información sobre herramientas. Dependiendo del estado válido de la fila, se muestra un icono diferente:

    <igx-column field="row_valid" header=" " [editable]="false" [pinned]="true" [width]="'50px'">
        <ng-template igxCell let-cell="cell">
            <div *ngIf="isRowValid(cell)" [igxTooltipTarget]="tooltipRef"  style="margin-right: '-10px';">
                <img width="18" src="assets/images/grid/active.png"/>
            </div>
            <div *ngIf="!isRowValid(cell)" [igxTooltipTarget]="tooltipRef" style="margin-right: '-10px';">
                <img width="18" src="assets/images/grid/expired.png"/>
            </div>
            <div #tooltipRef="tooltip" igxTooltip [style.width]="'max-content'">
                <div *ngFor="let message of stateMessage(cell)">
                    {{message}}
                </div>
            </div>
        </ng-template>
    </igx-column>
    

    Los mensajes de error se recopilan en la función stateMessage, que recopila los errores de cada celda, porque cada columna podría tener validaciones de formularios con plantilla y luego verifica los errores de la fila misma, que provienen del rowValidator personalizado.

    public stateMessage(cell: CellType) {
        const messages = [];
        const row = cell.row;
        const cellValidationErrors = row.cells.filter(x => !!x.validation.errors);
        cellValidationErrors.forEach(cell => {
            if (cell.validation.errors) {
                if (cell.validation.errors.required) {
                    messages.push(`The \`${cell.column.header}\` column is required.`);
                }
                // Other cell errors ...
            }
        });
    
        if (row.validation.errors?.createdInvalid) {
            messages.push(`The \`Date of Registration\` date cannot be in the future.`);
        }
        // Other cross-field errors...
    
        return messages;
    }
    
    

    Cross-field example

    El siguiente ejemplo demuestra la validación entre campos en acción.

    Estilismo

    Usando la Ignite UI for Angular, podemos modificar los estilos de validación predeterminados durante la edición.

    En el siguiente ejemplo, utilizaremos la plantilla expuesta para el mensaje de validación, que aparece en una información sobre herramientas y anula el color del error para modificar la apariencia predeterminada de la validación. También aplicaremos estilo al fondo de las filas no válidas para hacerlas más distintas.

    Import theme

    La forma más sencilla de diseñar y acceder a variables CSS es definir estilos en el archivo de estilo global de nuestra app (normalmente styles.scss). Lo primero que debemos hacer es importar el archivo themes/index; esto nos da acceso a todas las poderosas herramientas de Ignite UI for Angular Sass:

    @use "igniteui-angular/theming" as *;
    
    // IMPORTANT: Prior to Ignite UI for Angular version 13 use:
    // @import '~igniteui-angular/lib/core/styles/themes/index';
    

    Include the styles

    Para cambiar el color del error puedes usar la variable css--igx-error-500:

    --igx-error-500: 34, 80%, 63%;
    

    Custom Templates

    Cambiar la plantilla de error predeterminada permite configurar clases y estilos personalizados:

    <ng-template igxCellValidationError let-cell='cell' let-defaultErr='defaultErrorTemplate'>
        <div class="validator-container">
            <ng-container *ngTemplateOutlet="defaultErr">
            </ng-container>
        </div>
    </ng-template>
    

    Invalid row and cell styles

    Las filas y celdas proporcionan una API para que los desarrolladores sepan si una fila o celda no es válida y qué tipo de errores están activos.

    public rowStyles = {
        background: (row: RowType) => row.validation.status === 'INVALID' ? '#FF000033' : '#00000000'
    };
    public cellStyles = {
        'invalid-cell': (rowData, columnKey) => {
            const pKey = this.grid.primaryKey;
            const cell = this.grid.getCellByKey(rowData[pKey], columnKey);
            return cell && cell.validation.status === 'INVALID';
        }
    }
    
    <igx-grid [rowStyles]="rowStyles">
        <igx-column field="ReorderLevel" header="ReorderLever" required [cellClasses]="cellStyles">
    

    Demo

    API References

    Known Issues and Limitations

    Limitación Descripción
    CuandovalidationTrigger es borroso,editValue y la validación se activará solo después de que el editor esté borroso. La razón es que esto utiliza el formControlupdateOn propiedad. Esto determina el evento en el que formControl se actualizará y activará los validadores relacionados.

    Additional Resources

    Nuestra comunidad es activa y siempre da la bienvenida a nuevas ideas.