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
Nós estendemos algumas das diretivas do validador Angular Forms para trabalhar diretamente com o IgxColumn
. Os mesmos validadores estão disponíveis como atributos para serem definidos declarativamente em igx-column
. Os seguintes validadores são suportados prontos para uso:
- obrigatório
- mínimo
- máx.
- 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é-criadas required
, email
e min
validator em uma grade.
Configure via reactive forms
Expomos o FormGroup
que será usado para validação quando a edição começar em uma linha/célula por meio de um evento formGroupCreated
. 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 por meio da propriedade validation
. Esse serviço tem as seguintes APIs públicas:
valid
- retorna se o estado de validação da grade é válido.getInvalid
- retorna registros com estados inválidos.clear
- limpa o estado do registro por id ou limpa todos os estados 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:
- Durante a edição via editor de células com base no
validationTrigger
da grade. Ou nachange
durante a digitação no editor, ou noblur
quando o editor perde o foco ou fecha. - Ao atualizar células/linhas via API -
updateRow
,updateCell
etc. - Ao usar a edição em lote e a API
undo
/redo
do serviço de transação.
Observação: a validação não será acionada para registros que não foram editados por meio da entrada do usuário ou da API de edição. Os indicadores visuais na célula serão exibidos somente se a entrada relacionada for considerada tocada - seja por meio da interação do usuário ou da API
markAsTouched
do serviço de validação.
Angular Grid Validation Customization Options
Set a custom validator
Você pode definir sua própria diretiva de validação para usar em uma <igx-column>
no 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 proibir o envio de um valor inválido nos dados. Nesses cenários, você pode usar os eventos cellEdit
ou rowEdit
e cancelar o evento caso o novo valor seja inválido. Os argumentos de ambos os eventos têm uma propriedade valid
e podem ser cancelados de acordo. Como ele é usado pode ser visto no exemplo Cross-field Validation
<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 por meio de seu FormGroup
compartilhado.
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 entre campos pode ser adicionado ao formGroup
da linha do evento formGroupCreated
, que retorna o novo formGroup
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 na função stateMessage
, que reúne os erros de cada célula, porque cada coluna pode ter validações de formulário modeladas e, em seguida, verifica os erros da própria linha, que vêm do 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
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 no arquivo de estilo global do nosso app
(normalmente styles.scss
). A primeira coisa que precisamos fazer é importar o arquivo themes/index
- 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 alterar a cor do erro você pode usar a variável css--igx-error-500
:
--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
- Crie operações CRUD com igxGrid
- Visão geral da grade
- Edição de grade
- Edição de linha de grade
- Adição de linha de grade
- Transações de Grade