Angular Tree Grid Editing and Validation
A edição da Grade de Árvore 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 de árvore.
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-tree-grid (formGroupCreated)='formCreateHandler($event)' ...>
public formCreateHandler(args: IGridFormGroupCreatedEventArgs) {
const formGroup = args.formGroup;
const hireDateRecord = formGroup.get('HireDate');
hireDateRecord.addValidators([this.futureDateValidator(), 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 Tree 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-tree-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 se uma cidade especificada para uma pessoa está no país atualmente definido e vice-versa. Verifique também se a idade de uma pessoa já era de 18 anos quando foi contratada.
As próximas linhas de código mostram a função validadora de campo cruzado, que contém as comparações descritas acima e define os erros relacionados.
private rowValidator(): ValidatorFn {
return (formGroup: FormGroup): ValidationErrors | null => {
let returnObject = {};
const age = formGroup.get('Age');
const hireDate = formGroup.get('HireDate');
if((new Date().getFullYear() - new Date(hireDate.value).getFullYear()) + 18 >= age.value) {
returnObject['ageLessHireDate'] = true;
}
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;
};
}
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-tree-grid igxPreventDocumentScroll #treeGrid [batchEditing]="true" [data]="data" primaryKey="ID"
foreignKey="ParentID" [width]="'100%'" [height]="'500px'" [rowEditable]="true" [pinning]="pinningConfig"
(formGroupCreated)="formCreateHandler($event)">
<!-- ... -->
</igx-tree-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" [dataType]="'number'" [pinned]="true" [width]="'150px'">
<ng-template igxCell let-cell="cell">
<div *ngIf="isRowValid(cell)" [igxTooltipTarget]="tooltipRef" style="margin: 'auto';">
<img width="18" src="assets/images/grid/active.png"/>
</div>
<div *ngIf="!isRowValid(cell)" [igxTooltipTarget]="tooltipRef" style="margin: 'auto';">
<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?.ageLessHireDate) {
messages.push(`\`Age\` cannot be less than 18 when the person was hired.`);
}
if (row.validation.errors?.invalidAddress) {
messages.push(`Selected \`City\` does not match the \`Country\`.`);
}
if (messages.length === 0 && this.isRowValid(cell)) {
messages.push('OK');
}
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.cells.find(c => c.validation.errors !== null && c.validation.errors !== undefined) ? '#FF000033' : '#00000000'
};
public cellStyles = {
'invalid-cell': (rowData, columnKey) => {
const pKey = this.treeGrid.primaryKey;
const cell = this.treeGrid.getCellByKey(rowData[pKey], columnKey);
return cell && cell.validation.status === 'INVALID';
}
}
<igx-tree-grid [rowStyles]="rowStyles">
<igx-column *ngFor="let c of columns" [field]="c.field" [dataType]="c.dataType" [header]="c.label" [required]="c.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 de árvore
- Edição de grade de árvore
- Edição de linhas da grade de árvore
- Adicionando Linha de Grade de Árvore
- Tree Grid Transactions