Carga de grade hierárquica sob demanda
O Ignite UI for Angular IgxHierarchicalGrid
permite uma renderização rápida, solicitando a quantidade mínima de dados a serem recuperados do servidor para que o usuário possa ver o resultado em exibição e interagir com os dados visíveis o mais rápido possível. Inicialmente, apenas os dados da grade raiz são recuperados e renderizados, somente depois que o usuário expandir uma linha contendo uma grade filho, ele receberá os dados dessa grade filho específica. Esse mecanismo, também conhecido como Load on Demand, pode ser facilmente configurado para funcionar com qualquer dado remoto.
Este tópico demonstra como configurar o Load on Demand solicitando dados de uma WebAPI Northwind. Aqui está a demonstração de trabalho e, mais tarde, vamos analisá-la passo a passo e descrever o processo de criação.
Angular Hierarchical Grid Load On Demand Example
Hierarchical Grid Setup
Vamos configurar nossa grade hierárquica. Primeiro, definiremos nosso modelo de grade hierárquica com os níveis de hierarquia que esperamos ter. Sabemos que nossa grade primaryKey
raiz para os clientes é deles customerId
, para seus pedidos no primeiro nível -orderId
e respectivamente para detalhes do pedido -productId
. Conhecer cada tabela de banco de dados e suas chaves nos permite definir nosso modelo inicial:
<igx-hierarchical-grid #hGrid [primaryKey]="'customerId'" [autoGenerate]="true" [height]="'600px'" [width]="'100%'">
<igx-row-island [key]="'Orders'" [primaryKey]="'orderId'" [autoGenerate]="true">
<igx-row-island [key]="'Details'" [primaryKey]="'productId'" [autoGenerate]="true">
</igx-row-island>
</igx-row-island>
</igx-hierarchical-grid>
Definiremos facilmente os dados da grade raiz depois de obter seus dados do endpoint em nosso código posteriormente, pois podemos usar a #hGrid
referência. Definir os dados para qualquer filho que foi expandido é um pouco diferente.
Quando uma linha é expandida pela primeira vez, um novo filho IgxHierarchicalGrid
é renderizado para ela e precisamos obter a referência da grade recém-criada para definir seus dados. É por isso que cada IgxRowIsland
componente fornece o gridCreated
evento que é acionado quando uma nova grade filho é criada para essa ilha de linha específica. Podemos usar isso para obter a referência necessária para a nova grade, solicitar seus dados do endpoint e aplicá-los.
Podemos usar um método para todas as ilhas de linha, pois o endpoint só precisa da chave da ilha de linha, da chave primária da linha pai e de seu identificador exclusivo. Todas essas informações podem ser acessadas diretamente dos argumentos do evento.
Configuração da indicação de carga
Agora vamos melhorar a experiência do usuário informando ao usuário que os dados ainda estão sendo carregados para que ele não precise olhar para uma grade vazia enquanto isso. É por isso que o suporta IgxHierarchicalGrid
um indicador de carga que pode ser exibido enquanto a grade está vazia.
Exibimos um indicador de carregamento definindo a isLoading
propriedade como true
enquanto não houver dados. Precisamos configurá-lo inicialmente para a grade raiz e também ao criar novas grades filhas, até que seus dados sejam carregados. Sempre podemos defini-lo em true
nosso modelo, mas queremos ocultá-lo (definindo-o como false
) e exibir que a grade não tem dados se o serviço retornar uma matriz vazia.
Por fim, vamos desativar a autoGenerate
propriedade e definir a coleção de colunas na marcação.
O arquivo hierarchical-grid-lod.component.html
de modelo, após todas as alterações adicionadas, ficaria assim:
<igx-hierarchical-grid #hGrid [data]="remoteData" [isLoading]="true" [primaryKey]="'customerId'" [autoGenerate]="false" [height]="'580px'" [width]="'100%'" [igxPreventDocumentScroll]="true" [allowAdvancedFiltering]="true" [schema]="schema" (advancedFilteringExpressionsTreeChange)="refreshRootGridData()">
<igx-grid-toolbar></igx-grid-toolbar>
<igx-column field="customerId" [dataType]="'string'"></igx-column>
<igx-column field="companyName" [dataType]="'string'"></igx-column>
<igx-column field="contactName" [dataType]="'string'"></igx-column>
<igx-column field="contactTitle" [dataType]="'string'"></igx-column>
<igx-row-island #rowIsland1 [key]="'Orders'" [primaryKey]="'orderId'" [autoGenerate]="false" (gridCreated)="gridCreated($event)">
<igx-column field="orderId"></igx-column>
<igx-column field="customerId"></igx-column>
<igx-column field="shipVia"></igx-column>
<igx-column field="freight"></igx-column>
<igx-row-island #rowIsland2 [key]="'Details'" [primaryKey]="'orderId'" [autoGenerate]="false" (gridCreated)="gridCreated($event)">
<igx-column field="orderId"></igx-column>
<igx-column field="productId"></igx-column>
<igx-column field="unitPrice"></igx-column>
<igx-column field="quantity"></igx-column>
<igx-column field="discount"></igx-column>
</igx-row-island>
</igx-row-island>
</igx-hierarchical-grid>
Advanced filtering
Para usar a IgxHierarchicalGrid
Filtragem Avançada no com carga sob demanda, você precisa definir a schema
propriedade da grade para uma entidade com estrutura hierárquica, especificando entidades filhas e campos com seus tipos de dados. Isso garante que as expressões de filtragem com consultas aninhadas possam ser criadas antes mesmo de qualquer dado de grade filho ser carregado e que a grade possa interpretar e aplicar corretamente esses filtros aos dados.
No nosso caso, esta é a estrutura hierárquica correta:
public schema: EntityType[] = [
{
name: 'Customers',
fields: [
{ field: 'customerId', dataType: 'string' },
{ field: 'companyName', dataType: 'string' },
{ field: 'contactName', dataType: 'string' },
{ field: 'contactTitle', dataType: 'string' }
],
childEntities: [
{
name: 'Orders',
fields: [
{ field: 'customerId', dataType: 'string' },
{ field: 'orderId', dataType: 'number' },
{ field: 'employeeId', dataType: 'number' },
{ field: 'shipVia', dataType: 'string' },
{ field: 'freight', dataType: 'number' }
],
childEntities: [
{
name: 'Details',
fields: [
{ field: 'orderId', dataType: 'number' },
{ field: 'productId', dataType: 'number' },
{ field: 'unitPrice', dataType: 'number' },
{ field: 'quantity', dataType: 'number' },
{ field: 'discount', dataType: 'number' }
]
}
]
}
]
}
];
Configurando o filtro inicial
Agora vamos adicionar regras de filtragem iniciais à nossa grade para que a grade raiz seja filtrada quando carregada pela primeira vez. Vamos criar um FilteringExpressionsTree
e defini-lo como a advancedFilteringExpressionsTree
propriedade do gancho usando o ngOnInit
ciclo de IgxHierarchicalGrid
vida.
Digamos que queremos filtrar os clientes que têm pelo menos 500
o frete do pedido. Aproveitaremos a capacidade de criar consultas aninhadas nas expressões de filtragem e este é o resultado:
public ngOnInit() {
const ordersTree = new FilteringExpressionsTree(FilteringLogic.And, undefined, 'Orders', ['customerId']);
ordersTree.filteringOperands.push({
fieldName: 'freight',
ignoreCase: false,
condition: IgxNumberFilteringOperand.instance().condition('greaterThanOrEqualTo'),
conditionName: IgxNumberFilteringOperand.instance().condition('greaterThanOrEqualTo').name,
searchVal: '500'
});
const customersTree = new FilteringExpressionsTree(FilteringLogic.And, undefined, 'Customers', ['customerId', 'companyName', 'contactName', 'contactTitle']);
customersTree.filteringOperands.push({
fieldName: 'customerId',
condition: IgxStringFilteringOperand.instance().condition('inQuery'),
conditionName: IgxStringFilteringOperand.instance().condition('inQuery').name,
ignoreCase: false,
searchTree: ordersTree
});
this.hGrid.advancedFilteringExpressionsTree = customersTree;
}
Connecting to the endpoint
Estaremos nos comunicando com o endpoint pelo protocolo HTTP usando a interface XMLHttpRequest que os navegadores fornecem. Para conseguir isso com mais facilidade, usaremos o módulo do HttpClient
Angular que oferece uma API HTTP de cliente simplificada.
Obtendo dados da grade raiz
A Northwind WebAPI nos fornece um endpoint POST que aceita um IFilteringExpressionsTree
como parâmetro e o usaremos para aproveitar a funcionalidade de filtragem avançada na IgxHierarchicalGrid
grade raiz. Faremos isso no refreshRootGridData
método:
public refreshRootGridData() {
const tree = this.hGrid.advancedFilteringExpressionsTree;
this.hGrid.isLoading = true;
if (tree) {
this.http.post(`${API_ENDPOINT}/QueryBuilder/ExecuteQuery`, tree).subscribe(data =>{
this.remoteData = Object.values(data)[0];
this.hGrid.isLoading = false;
this.hGrid.cdr.detectChanges();
});
} else {
this.http.get(`${API_ENDPOINT}/Customers`).subscribe(data => {
this.remoteData = Object.values(data);
this.hGrid.isLoading = false;
this.hGrid.cdr.detectChanges();
});
}
}
Como você pode ver this.http
, haverá uma referência ao nosso HttpCLient
módulo. O subscribe
método faz parte do Observable do Angular e é usado para lidar com a resposta assíncrona da solicitação HTTP. Quando os dados são recebidos, ele atribui os dados buscados à grade relevante, atualiza seu estado de carregamento para falso e dispara a detecção de alterações para garantir que a interface do usuário reflita as alterações.
Para carregar os dados depois que a grade raiz for inicialmente renderizada, usaremos o gancho do ngAfterViewInit
ciclo de vida e chamaremos o refreshRootGridData
método:
public ngAfterViewInit() {
this.refreshRootGridData();
}
Obtendo dados de grades filho
Em seguida, definiremos como devemos criar nossa URL para a solicitação GET para obter os dados de nossas grades filhas. Esta é a representação visual das relações entre as tabelas:

Por fim, precisamos implementar nosso gridCreated
método que solicitará dados para qualquer nova grade filho criada. Será semelhante a obter os dados da grade de nível raiz, só que desta vez usaremos os dados fornecidos no evento gridCreated
e construiremos nossa URL com eles:
public gridCreated(event: IGridCreatedEventArgs) {
event.grid.isLoading = true;
const url = this.buildUrl(event);
this.http.get(url).subscribe(data => {
event.grid.data = Object.values(data);
event.grid.isLoading = false;
this.hGrid.cdr.detectChanges();
});
}
private buildUrl(event: IGridCreatedEventArgs) {
const parentKey = (event.grid.parent as any).key ?? this.schema[0].name;
const url = `${API_ENDPOINT}/${parentKey}/${event.parentID}/${event.owner.key}`;
return url;
}