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 criando um Remote Service Provider que se comunica com um Remote oData v4 Service já disponível. Aqui está a demonstração de trabalho e, mais tarde, iremos analisá-la passo a passo e descrever o processo de criação.
Angular Hierarchical Grid Load On Demand Example
Remote Service Provider
Primeiro, prepararemos nosso provedor de serviços para que estejamos prontos para obter os dados necessários para a grade hierárquica.
Obtendo dados básicos
Estaremos nos comunicando com nosso serviço de back-end 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. Dessa forma, para obter nossos dados, precisaremos deste método simples em nosso serviço:
public getData(dataState): Observable<any[]> {
return this.http.get(this.buildUrl(dataState)).pipe(
map(response => response['value']),
);
}
Como você pode ver this.http
, será uma referência ao nosso HttpCLient
módulo e buildUrl()
será o método que gerará nossa url com base nos dados que recebemos. Mapeamos nossa resposta para obter apenas o valor de nosso resultado e retornar um Observable, já que isso é executado de forma assíncrona. Dessa forma, podemos subscrevê-lo posteriormente, processá-lo ainda mais em nosso aplicativo e passá-lo para nossa grade.
Construindo nossa URL de solicitação
Em seguida, definiremos como devemos construir nossa URL para a solicitação GET. É aqui que poderemos obter os dados para nossa grade principal, mas também para qualquer grade secundária dentro dela. Usaremos os Customers
dados daqui para nosso nível raiz e uso Order
e Order_Details
para os níveis inferiores. O modelo será diferente por aplicativo, mas usaremos o seguinte:

O que precisamos primeiro é da key
nossa tabela para determinar de onde obter os dados para a grade desejada, a chave primária da linha pai e seu ID exclusivo. Vamos definir tudo isso em uma interface chamada IDataState
. Um exemplo:
export interface IDataState {
key: string;
parentID: any;
parentKey: string;
rootLevel: boolean;
}
//...
public buildUrl(dataState: IDataState): string {
let qS = "";
if (dataState) {
qS += `${dataState.key}?`;
if (!dataState.rootLevel) {
if (typeof dataState.parentID === "string") {
qS += `$filter=${dataState.parentKey} eq '${dataState.parentID}'`;
} else {
qS += `$filter=${dataState.parentKey} eq ${dataState.parentID}`;
}
}
}
return `${this.url}${qS}`;
}
//...
Resultado
Finalmente, é assim que o nosso remote-lod.service.ts
seria:
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
export interface IDataState {
key: string;
parentID: any;
parentKey: string;
rootLevel: boolean;
}
@Injectable()
export class RemoteLoDService {
url = `https://services.odata.org/V4/Northwind/Northwind.svc/`;
constructor(private http: HttpClient) { }
public getData(dataState: IDataState): Observable<any[]> {
return this.http.get(this.buildUrl(dataState)).pipe(
map((response) => response['value'])
);
}
public buildUrl(dataState: IDataState): string {
let qS = "";
if (dataState) {
qS += `${dataState.key}?`;
if (!dataState.rootLevel) {
if (typeof dataState.parentID === "string") {
qS += `$filter=${dataState.parentKey} eq '${dataState.parentID}'`;
} else {
qS += `$filter=${dataState.parentKey} eq ${dataState.parentID}`;
}
}
}
return `${this.url}${qS}`;
}
}
Hierarchical Grid Setup
Em seguida, configuraremos nossa grade hierárquica e a conectaremos ao nosso provedor de serviços remotos.
Definição de modelo
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]="false" [height]="'600px'" [width]="'100%'">
<igx-column field="CustomerID" [hidden]="true"></igx-column>
<igx-column field="CompanyName"></igx-column>
<igx-column field="ContactName"></igx-column>
<igx-column field="ContactTitle"></igx-column>
<igx-column field="Country"></igx-column>
<igx-column field="Phone"></igx-column>
<igx-row-island [key]="'Orders'" [primaryKey]="'OrderID'" [autoGenerate]="false" >
<igx-column field="OrderID" [hidden]="true"></igx-column>
<igx-column field="ShipCountry"></igx-column>
<igx-column field="ShipCity"></igx-column>
<igx-column field="ShipAddress"></igx-column>
<igx-column field="OrderDate"></igx-column>
<igx-row-island [key]="'Order_Details'" [primaryKey]="'ProductID'" [autoGenerate]="false" >
<igx-column field="ProductID" [hidden]="true"></igx-column>
<igx-column field="Quantity"></igx-column>
<igx-column field="UnitPrice"></igx-column>
<igx-column field="Discount"></igx-column>
</igx-row-island>
</igx-row-island>
</igx-hierarchical-grid>
No entanto, há uma coisa faltando em nosso modelo, que são os dados para nossa grade hierárquica de nível raiz e, eventualmente, seus filhos. Definiremos facilmente os dados da grade raiz depois de obter seus dados do serviço 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 serviço e aplicá-los.
Podemos usar um método para todas as ilhas de linha, já que construímos nosso serviço de modo que ele precise apenas de informações se for o nível raiz, a chave da ilha de linha, a chave primária da linha pai e seu identificador exclusivo. Todas essas informações podem ser acessadas diretamente dos argumentos do evento ou da ilha de linha responsável por disparar o evento.
Vamos nomear o método que usaremos gridCreated
. Como o evento gridCreated
fornece a parentID
propriedade, uma referência à ilha de linha como owner
e à nova propriedade filho grid
, ela será passada como o primeiro argumento. Faltam apenas informações sobre a linha primaryKey
pai, mas podemos facilmente passar isso como um segundo argumento, dependendo de qual ilha de linha vinculamos.
O arquivo hierarchical-grid-lod.component.html
de modelo, com essas alterações adicionadas, ficaria assim:
<igx-hierarchical-grid #hGrid [primaryKey]="'CustomerID'" [autoGenerate]="false" [height]="'600px'" [width]="'100%'">
<igx-column field="CustomerID" [hidden]="true"></igx-column>
<igx-column field="CompanyName"></igx-column>
<igx-column field="ContactName"></igx-column>
<igx-column field="ContactTitle"></igx-column>
<igx-column field="Country"></igx-column>
<igx-column field="Phone"></igx-column>
<igx-row-island [key]="'Orders'" [primaryKey]="'OrderID'" [autoGenerate]="false" (gridCreated)="gridCreated($event, 'CustomerID')">
<igx-column field="OrderID" [hidden]="true"></igx-column>
<igx-column field="ShipCountry"></igx-column>
<igx-column field="ShipCity"></igx-column>
<igx-column field="ShipAddress"></igx-column>
<igx-column field="OrderDate"></igx-column>
<igx-row-island [key]="'Order_Details'" [primaryKey]="'ProductID'" [autoGenerate]="false" (gridCreated)="gridCreated($event, 'OrderID')">
<igx-column field="ProductID" [hidden]="true"></igx-column>
<igx-column field="Quantity"></igx-column>
<igx-column field="UnitPrice"></igx-column>
<igx-column field="Discount"></igx-column>
</igx-row-island>
</igx-row-island>
</igx-hierarchical-grid>
Conectando nosso serviço
Uma de nossas etapas finais agora será conectar nosso serviço criado anteriormente à nossa grade hierárquica. Como o definimos como um Injectable
, podemos passá-lo como um provedor para nosso aplicativo. Também obteremos uma referência à nossa grade raiz, usando ViewChild
query para definir seus dados:
@Component({
providers: [RemoteLoDService],
selector: "app-hierarchical-grid-lod",
styleUrls: ["./hierarchical-grid-lod.component.scss"],
templateUrl: "./hierarchical-grid-lod.component.html"
})
export class HierarchicalGridLoDSampleComponent {
@ViewChild("hGrid")
public hGrid: IgxHierarchicalGridComponent;
constructor(private remoteService: RemoteLoDService) { }
}
Para garantir que a grade seja renderizada antes de solicitarmos seus dados do serviço e atribuí-los, usaremos o gancho do AfterViewInit
ciclo de vida. Como não tem pais só podemos passar rootLevel
que é true
, e a chave para isso, para o getData
nosso serviço. Como ele retorna um observável, precisaremos assiná-lo:
public ngAfterViewInit() {
this.remoteService.getData({ parentID: null, rootLevel: true, key: "Customers" }).subscribe((data) => {
this.hGrid.data = data;
this.hGrid.cdr.detectChanges();
});
}
Em seguida, precisamos apenas criar nosso gridCreated
método que solicitará dados para qualquer nova grade filha criada. Será semelhante a obter os dados da grade de nível raiz, só que desta vez precisaremos passar mais informações, como parentID
e parentKey
. rootLevel
false
será para qualquer criança:
public gridCreated(event: IGridCreatedEventArgs, _parentKey: string) {
const dataState = {
key: event.owner.key,
parentID: event.parentID,
parentKey: _parentKey,
rootLevel: false
};
this.remoteService.getData(dataState).subscribe(
(data) => {
event.grid.data = data;
event.grid.cdr.detectChanges();
}
);
}
Com isso, a configuração do nosso aplicativo está quase pronta. Esta última etapa visa 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. Se novos dados forem recebidos, o indicador de carregamento será ocultado e os dados serão renderizados.
Configuração da indicação de carga
O IgxHierarchicalGrid
pode exibir 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 configurá-lo em true
nosso modelo, mas queremos ocultá-lo e exibir que a grade não tem dados se o serviço retornar uma matriz vazia definindo-a como false
.
Nesse caso, a versão final do nosso hierarchical-grid-lod.component.ts
ficaria assim:
import { AfterViewInit, Component, ViewChild } from "@angular/core";
import {
IGridCreatedEventArgs,
IgxHierarchicalGridComponent,
IgxRowIslandComponent
} from "igniteui-angular";
import { RemoteLoDService } from "../services/remote-lod.service";
@Component({
providers: [RemoteLoDService],
selector: "app-hierarchical-grid-lod",
styleUrls: ["./hierarchical-grid-lod.component.scss"],
templateUrl: "./hierarchical-grid-lod.component.html"
})
export class HierarchicalGridLoDSampleComponent implements AfterViewInit {
@ViewChild("hGrid")
public hGrid: IgxHierarchicalGridComponent;
constructor(private remoteService: RemoteLoDService) { }
public ngAfterViewInit() {
this.hGrid.isLoading = true;
this.remoteService.getData({ parentID: null, rootLevel: true, key: "Customers" }).subscribe((data) => {
this.hGrid.isLoading = false;
this.hGrid.data = data;
this.hGrid.cdr.detectChanges();
});
}
public gridCreated(event: IGridCreatedEventArgs, _parentKey: string) {
const dataState = {
key: event.owner.key,
parentID: event.parentID,
parentKey: _parentKey,
rootLevel: false
};
event.grid.isLoading = true;
this.remoteService.getData(dataState).subscribe(
(data) => {
event.grid.isLoading = false;
event.grid.data = data;
event.grid.cdr.detectChanges();
}
);
}
}