Edição e validação de grade Angular

    A edição do Grid expõe um mecanismo de validação integrado da entrada do usuário ao editar células/linhas. Ele estende a funcionalidade de validação do Angular Form para permitir uma integração mais fácil com uma funcionalidade bem conhecida. Quando o estado do editor muda, indicadores visuais são aplicados à célula editada.

    Configuração

    Configure via template-driven configuration

    Estendemos algumas das diretivas do validador do Angular Forms para trabalhar diretamente com oIgxColumn. Os mesmos validadores estão disponíveis como atributos a serem definidos declarativamente em.igx-column Os seguintes validadores são suportados de fábrica:

    • obrigatório
    • mínimo
    • máx.
    • e-mail
    • comprimento mínimo
    • comprimento máximo
    • padrão

    Para validar que uma entrada de coluna será definida e o valor será formatado como um e-mail, você pode usar as diretivas relacionadas:

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

    O exemplo a seguir demonstra como usar as diretivas pré-construídasrequiredemail emin do validador em uma Grade.

    Configure via reactive forms

    Expomos oFormGroup que será usado para validação quando a edição começar em uma linha/célula via eventoformGroupCreated. Você pode modificá-lo adicionando seus próprios validadores para os 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());
        }
    

    Você pode decidir escrever sua própria função validadora ou usar uma das funções validadoras integradas Angular.

    Validation service API

    A grade expõe um serviço de validação via avalidation propriedade. Esse serviço possui as seguintes APIs públicas:

    • valid- retorna se o estado de validação da grade for válido.
    • getInvalid- retorna registros com estados inválidos.
    • clear- Libera o estado para registro por ID ou elimina todo o estado se nenhum ID for fornecido.
    • markAsTouched- marca o registro/campo relacionado como tocado.

    Os estados inválidos persistirão até que os erros de validação neles sejam corrigidos de acordo com a regra de validação ou sejam limpos.

    Validation triggers

    A validação será acionada nos seguintes cenários:

    • Enquanto edita via o editor de células baseado na gradevalidationTrigger. Ou ligadochange enquanto digita no editor, ou quandoblur o editor perde o foco ou fecha.
    • Ao atualizar células/linhas via API -updateRow,updateCell etc.
    • Ao usar edição em lote e a/undoredo API do serviço de transação.

    Nota: A validação não será acionada para registros que não foram editados via entrada do usuário ou via API de edição. Indicadores visuais na célula só serão mostrados se a entrada relacionada for considerada tocada – seja por interação do usuário ou pelamarkAsTouched API do serviço de validação.

    Angular Grid Validation Customization Options

    Set a custom validator

    Você pode definir sua própria diretriz de validação para usar no<igx-column> modelo.

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

    Depois de definido e adicionado ao módulo do seu aplicativo, você pode defini-lo declarativamente para uma determinada coluna na grade:

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

    Change default error template

    Você pode definir seu próprio modelo de erro personalizado que será exibido na dica de ferramenta de erro quando a célula entrar em estado inválido. Isso é útil em cenários em que você deseja adicionar sua própria mensagem de erro personalizada ou alterar a aparência ou o conteúdo da mensagem.

    <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

    Em alguns casos, você pode querer impedir o envio de um valor inválido nos dados. Nesses cenários, você pode usar oscellEdit eventos ourowEdit e cancelar o evento caso o novo valor seja inválido. Os argumentos de ambos os eventos têm umavalid propriedade e podem ser cancelados de acordo. Como ele é usado pode ser visto no exemplo de Validação Cruzada de Campo

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

    Example

    O exemplo abaixo demonstra as opções de personalização mencionadas acima.

    Cross-field validation

    Em alguns cenários, a validação de um campo pode depender do valor de outro campo no registro. Nesse caso, um validador personalizado pode ser usado para comparar os valores no registro via seu compartilhamentoFormGroup.

    O exemplo abaixo demonstra uma validação de campo cruzado entre diferentes campos do mesmo registro. Ele verifica a validade das datas em comparação com a data atual e entre a data ativa e a data de criação do registro, bem como a proporção de negócios ganhos/perdidos para cada funcionário. Todos os erros são coletados em uma coluna fixada separada que mostra que o registro é inválido e exibe os erros relacionados.

    As próximas linhas de código mostram a função validadora entre campos, que contém as comparações e define os erros relacionados a elas.

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

    O validador cross-field pode ser adicionado aoformGroup evento da linha de parteformGroupCreated, que retorna o novoformGroup para cada linha ao entrar no modo de edição:

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

    Os diferentes erros são exibidos em uma célula modelo que combina todos os erros em uma única dica de ferramenta. Dependendo do estado válido da linha, um ícone diferente é exibido:

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

    As mensagens de erro são reunidas nastateMessage função, que reúne os erros de cada célula, porque cada coluna pode ter validações de formulário com templates e então verifica os erros da própria linha, que vêm do customrowValidator.

    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

    O exemplo abaixo demonstra a validação entre campos em ação.

    Estilização

    Usando a Ignite UI for Angular, podemos alterar os estilos de validação padrão durante a edição.

    No exemplo abaixo, faremos uso do modelo exposto para mensagem de validação, que aparece em uma dica de ferramenta e substitui a cor do erro para modificar a aparência padrão da validação. Também estilizaremos o plano de fundo das linhas inválidas para torná-las mais distintas.

    Import theme

    A maneira mais fácil de estilizar e acessar variáveis CSS é definir estilos noapp nosso arquivo de estilo global (normalmentestyles.scss). A primeira coisa que precisamos fazer é importar othemes/index arquivo – isso nos dá acesso a todas as ferramentas poderosas do 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 mudar a cor de erro, você pode usar a variável--igx-error-500 css:

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

    Custom Templates

    Alterar o modelo de erro padrão permite definir classes e 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

    Linhas e células fornecem API para que os desenvolvedores saibam se uma linha ou célula é inválida e que tipo de erro está ativo.

    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

    Limitação Descrição
    QuandovalidationTrigger é borrão,editValue e a validação será acionada somente depois que o editor estiver desfocado. A razão é que isso utiliza o formControl'supdateOn propriedade. Isso determina o evento no qual o formControl atualizará e acionará validadores relacionados.

    Additional Resources

    Nossa comunidade é ativa e sempre acolhedora para novas ideias.