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;
    }
    

    API References

    Additional Resources

    Nossa comunidade é ativa e sempre acolhedora para novas ideias.