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

    Configure via template-driven configuration

    Extendemos algunas de las directivas validadoras de Angular Forms para trabajar directamente con elIgxColumn. Los mismos validadores están disponibles como atributos para establecer declarativamente 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>
    

    The following sample demonstrates how to use the prebuilt required, email and min validator directives in a Hierarchical Grid.

    Configure via reactive forms

    Exponemos elFormGroup que se usará para validación cuando la edición empieza en una fila/celda mediante unformGroupCreated evento. Puedes modificarlo añadiendo tus propios validadores para los campos relacionados:

    <igx-hierarchical-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());
        }
    

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

    Validation service API

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

    • valid- retorna si el estado de validación de la cuadrícula es válido.
    • getInvalid- Retorna registros con estados inválidos.
    • clear- Borra el estado para el registro mediante ID o borra todo el estado si no se proporciona ningún identificador.
    • 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.

    Validation triggers

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

    • Mientras editas a través del editor de celdas basado en la cuadrículavalidationTrigger. Ya sea encendidochange mientras escribes en el editor, o cuandoblur el editor pierde el enfoque o cierra.
    • Al actualizar celdas/filas mediante la API -updateRow,updateCell etc.
    • Al usar edición por lotes y laundo /redo API del servicio de transacciones.

    Nota: La validación no se activará para registros que no hayan sido editados mediante 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 lamarkAsTouched API del servicio de validación.

    Angular Hierarchical Grid Validation Customization Options

    Set a custom validator

    Puedes definir tu propia directiva de validación para usar en<igx-column> 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 puede que quieras prohibir la presentación de un valor inválido en los datos. En esos escenarios puedes usar loscellEdit eventos orowEdit y cancelar el evento en caso de que el nuevo valor no sea válido. Los argumentos de ambos eventos tienen unavalid propiedad y pueden ser cancelados en consecuencia. Cómo se utiliza puede verse en el ejemplo de Validación Cruzada

    <igx-hierarchical-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 casos, la validación de un campo puede depender del valor de otro campo en el registro. En ese caso, se puede usar un validador personalizado para comparar los valores del registro a través de su compartido.FormGroup

    Cross-field validators can be added to the formGroup on the formGroupCreated event. In them multiple fields can be compared for validity.

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

    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>
    

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

    Cross-field example

    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.

    Estilismo

    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.

    Import theme

    La forma más sencilla de styling y acceder a variables css es definir estilos enapp nuestro archivo de estilo global (normalmentestyles.scss). Lo primero que tenemos que hacer es importar elthemes/index archivo; esto nos da acceso a todas las herramientas potentes 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';
    

    Include the styles

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

    --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) => {
        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';
      }
    }
    
    <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">
    

    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.