Edición y validación de cuadrículas jerárquicas Angular

    La edición de la cuadrícula jerárquica expone un mecanismo de validación integrado de la entrada del usuario al editar celdas o filas. Amplía la funcionalidad de validación de 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

    Configurar mediante configuración basada en plantillas

    Ampliamos algunas de las directivas de validación Angular Forms para que funcionen directamente con IgxColumn. Los mismos validadores están disponibles como atributos que se pueden configurar de forma declarativa en igx-column. Los siguientes validadores son compatibles de manera predeterminada:

    • 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>
    html

    El siguiente ejemplo demuestra cómo utilizar las directivas de validador min, email y required prediseñadas en una cuadrícula jerárquica.

    EXAMPLE
    TS
    HTML
    SCSS

    ¿Te gusta esta muestra? Obtenga acceso a nuestro kit de herramientas de Ignite UI for Angular completo y comience a crear sus propias aplicaciones en minutos. Descárgalo gratis.

    Configurar mediante formularios reactivos

    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-hierarchical-grid (formGroupCreated)='formCreateHandler($event)' ...>
    html
        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());
        }
    ts

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

    API de servicio de validación

    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 que contengan se corrijan de acuerdo con la regla de validación o se borren.

    Activadores de validación

    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.

    Opciones de personalización de la validación de cuadrícula jerárquica Angular

    Establecer un validador personalizado

    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;
        }
    }
    ts

    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" ...>
    html

    Cambiar plantilla de error predeterminada

    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>
    html

    Evitar salir del modo de edición en estado no válido

    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-hierarchical-grid (cellEdit)='cellEdit($event)' ...>
    html
    public cellEdit(evt) {
      if (!evt.valid) {
        evt.cancel = true;
      }
    }
    ts

    Ejemplo

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

    EXAMPLE
    TS
    HTML
    SCSS

    App Builder | CTA Banner

    Validación entre campos

    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.

    Se pueden agregar validadores de campos cruzados al formGroup en el evento formGroupCreated. En ellos se pueden comparar varios campos para comprobar su validez.

    public formCreateCustomerHandler(event: IGridFormGroupCreatedEventArgs) {
          const formGroup = event.formGroup;
          formGroup.addValidators(this.addressValidator());
      }
    
      public formCreateOrderHandler(event: IGridFormGroupCreatedEventArgs) {
          const formGroup = event.formGroup;
          formGroup.addValidators(this.dateValidator());
      }
    
      public addressValidator(): ValidatorFn {
          return (control: AbstractControl): ValidationErrors | null => {
              const formGroup = control;
              let returnObject = {};
              const city = formGroup.get('City');
              const country = formGroup.get('Country');
              const validCities = this.countryData.get(country.value);
              if (!validCities || !validCities[city.value]) {
                  returnObject['invalidAddress'] = true;
              }
              return returnObject;
          }
      }
    
      public dateValidator(): ValidatorFn {
          return (control: AbstractControl): ValidationErrors | null => {
              const formGroup = control;
              let returnObject = {};
              const orderDate = formGroup.get('OrderDate').value;
              const shippedDate = formGroup.get('ShippedDate').value;
              if (new Date(shippedDate) < new Date(orderDate)) {
                  returnObject['invalidRange'] = true;
              }
              return returnObject;
          }
      }
    ts

    Los errores de varios campos se pueden mostrar en una columna fija separada.

    <igx-column field="row_valid" header=" " [editable]="false" [dataType]="'number'" [pinned]="true" [width]="'50px'">
            <ng-template igxCell let-cell="cell">
                <div *ngIf="isRowValid(cell)" [igxTooltipTarget]="tooltipRef"
                >
                    <img width="18" src="assets/images/grid/active.png"/>
                </div>
                <div *ngIf="!isRowValid(cell)" [igxTooltipTarget]="tooltipRef"
                >
                    <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>
    html

    Los errores y los mensajes detallados se pueden determinar en función de la validez de la fila y la celda.

        public isRowValid(cell: CellType) {
            const hasErrors = !!cell.row.validation.errors || cell.row.cells.some(x => !!x.validation.errors);
            return !hasErrors;
        }
    
        public stateMessage(cell: CellType) {
            const messages = [];
            const row = cell.row;
            if  (row.validation.errors?.invalidAddress) {
                messages.push('The address information is invalid. City does not match the Country.');
            }
            if  (row.validation.errors?.invalidRange) {
                messages.push('The ShippedDate cannot be before the OrderDate.');
            }
            const cellValidationErrors = row.cells.filter(x => !!x.validation.errors);
            if (cellValidationErrors && cellValidationErrors.length > 0) {
                const fields = cellValidationErrors.map(x => x.column.field).join(',');
                messages.push('The following fields are required: ' + fields);
            }
    
            if (messages.length === 0) {
                // no errors
                return ['Valid'];
            }
            return messages;
        }
    ts

    Ejemplo de campo cruzado

    El siguiente ejemplo demuestra la validación entre campos en una cuadrícula jerárquica tanto para los datos raíz como para los secundarios.

    EXAMPLE
    TS
    HTML
    SCSS

    Estilo

    Usando la biblioteca de temas de Ignite UI for Angular, podemos modificar los estilos de validación predeterminados mientras editamos.

    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.

    Importar tema

    La forma más fácil de diseñar y acceder a las variables css es definir estilos en nuestro app archivo de estilo global (típicamente styles.scss). Lo primero que tenemos que hacer es importar el themes/index archivo, esto nos da acceso a todas las potentes herramientas del framework 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';
    scss

    Incluir los estilos

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

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

    Plantillas personalizadas

    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>
    html

    Estilos de fila y celda no válidos

    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) => {
        let cell = this.hierarchicalGrid.getCellByKey(rowData, columnKey);
        // search in child grids
        if (!cell) {
          for (let grid of this.childGrid.gridAPI.getChildGrids()) {
            cell = grid.getCellByKey(rowData, columnKey);
            if (cell) break;
          }
        }
        return cell && cell.validation.status === 'INVALID';
      }
    }
    ts
    <igx-hierarchical-grid [rowStyles]="rowStyles">
      <igx-column field="Artist" [editable]="true" [dataType]="'string'" required [cellClasses]="cellStyles">
      ...
      <igx-row-island [key]="'Albums'" [rowStyles]="rowStyles">
        <igx-column field="Album" [editable]="true" [dataType]="'string'" required [cellClasses]="cellStyles">
    html

    Manifestación

    EXAMPLE
    TS
    HTML
    SCSS

    Referencias de API

    Problemas conocidos y limitaciones

    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.

    Recursos adicionales

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