Angular Edição e validação de grade hierárquica
A edição da Grade Hierárquica 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 de formulário Angular para permitir uma integração mais fácil com uma funcionalidade bem conhecida. Quando o estado do editor é alterado, os 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 prebuilt,and required
email
min
validator em uma grade hierárquica.
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-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());
}
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 Hierarchical 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-hierarchical-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.
Validadores de campo cruzado podem ser adicionados ao formGroup no formGroupCreated
evento. Neles, vários campos podem ser comparados quanto à validade.
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;
}
}
Os erros de vários campos podem ser exibidos em uma coluna fixada 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>
Os erros e as mensagens detalhadas podem ser determinados com base na validade da linha e da célula.
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
O exemplo abaixo demonstra a validação entre campos em uma Grade Hierárquica para os dados raiz e filho.
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) => {
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
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 hierárquica
- Edição de grade hierárquica
- Edição de linha de grade hierárquica
- Adição de linha de grade hierárquica
- Transações de grade hierárquica