계층적 그리드 로드 온디맨드

    Ignite UI for Angular IgxHierarchicalGrid 사용자가 가능한 한 빨리 결과를 보기에서 확인하고 눈에 보이는 데이터와 상호 작용할 수 있도록 서버에서 검색할 최소한의 데이터 양을 요청하여 빠른 렌더링을 허용합니다. 처음에는 루트 그리드의 데이터만 검색되고 렌더링됩니다. 사용자가 하위 그리드가 포함된 행을 확장한 후에만 해당 특정 하위 그리드에 대한 데이터를 받게 됩니다. 요청 시 로드라고도 하는 이 메커니즘은 모든 원격 데이터에 대해 작동하도록 쉽게 구성할 수 있습니다.

    이 항목에서는 이미 사용 가능한 원격 oData v4 서비스와 통신하는 원격 서비스 공급자를 만들어 요청 시 로드를 구성하는 방법을 보여줍니다. 여기에 작업 데모가 있으며 나중에 단계별로 살펴보고 제작 과정을 설명하겠습니다.

    Angular Hierarchical Grid Load On Demand Example

    Remote Service Provider

    먼저 계층적 그리드에 필요한 데이터를 얻을 수 있도록 서비스 공급자를 준비합니다.

    기본 데이터 가져오기

    브라우저가 제공하는 XMLHttpRequest 인터페이스를 사용하여 HTTP 프로토콜을 통해 백엔드 서비스와 통신하게 됩니다. 이를 보다 쉽게 달성하기 위해 단순화된 클라이언트 HTTP API를 제공하는 Angular의 HttpClient 모듈을 사용할 것입니다. 그런 식으로 데이터를 얻으려면 서비스에 다음과 같은 간단한 방법이 필요합니다.

    public getData(dataState): Observable<any[]> {
        return this.http.get(this.buildUrl(dataState)).pipe(
            map(response => response['value']),
        );
    }
    

    보시다시피 this.http​ ​HttpCLient 모듈에 대한 참조가 될 것이고 buildUrl() 우리가 받은 데이터를 기반으로 URL을 생성하는 메서드가 될 것입니다. 응답을 매핑하여 결과 값만 얻고 Observable을 반환합니다. 이는 비동기적으로 실행되기 때문입니다. 이렇게 하면 나중에 이를 구독하고 애플리케이션에서 추가로 처리한 후 그리드에 전달할 수 있습니다.

    요청 URL 작성

    다음으로 GET 요청에 대한 URL을 구축하는 방법을 정의합니다. 여기에서 메인 그리드뿐만 아니라 그 안에 있는 하위 그리드에 대한 데이터도 얻을 수 있습니다. 우리는 Customers 데이터 여기 우리의 루트 수준과 사용을 위해 Order 그리고 Order_Details 더 낮은 수준의 경우. 모델은 애플리케이션마다 다르지만 다음 모델을 사용하겠습니다.

    먼저 필요한 것은 원하는 그리드에 대한 데이터를 가져올 위치를 결정하기 위한 테이블의 key, 상위 행의 기본 키 및 고유 ID입니다. 우리는 IDataState 라는 인터페이스에서 이 모든 것을 정의할 것입니다. 예:

    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}`;
    }
    //...
    

    결과

    마지막으로, 우리의 remote-lod.service.ts 다음과 같습니다:

    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

    다음으로 계층적 그리드를 설정하고 이를 원격 서비스 공급자에 연결하겠습니다.

    템플릿 정의

    먼저 우리가 기대하는 계층 구조 수준을 사용하여 계층적 그리드 템플릿을 정의합니다. 우리는 고객의 루트 그리드 primaryKeyCustomerID 이고, 첫 번째 수준의 주문인 OrderID와 주문 세부 정보인 ProductID 라는 것을 알고 있습니다. 각 데이터베이스 테이블과 해당 키를 알면 초기 템플릿을 정의할 수 있습니다.

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

    하지만 우리 템플릿에는 한 가지 누락된 것이 있는데, 그것은 루트 수준 계층적 그리드에 대한 데이터이고 결국에는 그 하위 항목입니다. #hGrid 참조를 사용할 수 있으므로 나중에 코드의 서비스에서 데이터를 가져온 후 루트 그리드의 데이터를 쉽게 설정할 것입니다. 확장된 하위 항목에 대한 데이터 설정은 약간 다릅니다.

    행이 처음으로 확장되면 이에 대한 새로운 하위 IgxHierarchicalGrid가 렌더링되며 해당 데이터를 설정하려면 새로 생성된 그리드에 대한 참조를 가져와야 합니다. 이것이 바로 각 IgxRowIsland 구성 요소가 해당 특정 행 아일랜드에 대해 새 하위 그리드가 생성될 때 실행되는 gridCreated 이벤트를 제공하는 이유입니다. 이를 사용하여 새 그리드에 필요한 참조를 얻고, 서비스에서 해당 데이터를 요청하고, 적용할 수 있습니다.

    루트 수준, 행 아일랜드의 키, 상위 행의 기본 키 및 고유 식별자인 경우에만 정보가 필요하도록 서비스를 구축했기 때문에 모든 행 아일랜드에 대해 하나의 방법을 사용할 수 있습니다. 이 모든 정보는 이벤트 인수에서 직접 액세스하거나 이벤트 트리거를 담당하는 행 아일랜드에서 액세스할 수 있습니다.

    gridCreated 사용할 메소드의 이름을 지정하겠습니다. 이벤트 gridCreated​ ​parentID 속성, owner 로서의 행 아일랜드에 대한 참조 및 새 하위 grid 속성을 제공하므로 첫 번째 인수로 전달됩니다. 상위 행의 primaryKey에 대한 정보만 누락되었지만 바인딩하는 행 아일랜드에 따라 이를 두 번째 인수로 쉽게 전달할 수 있습니다.

    이러한 변경 사항이 추가된 템플릿 파일 hierarchical-grid-lod.component.html 다음과 같습니다.

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

    우리 서비스 연결하기

    이제 마지막 단계 중 하나는 이전에 생성된 서비스를 계층적 그리드에 연결하는 것입니다. Injectable로 정의했으므로 이를 애플리케이션에 공급자로 전달할 수 있습니다. ViewChild 쿼리를 사용하여 데이터를 설정하여 루트 그리드에 대한 참조도 얻습니다.

    @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) { }
    }
    

    서비스에서 데이터를 요청하고 할당하기 전에 외부 그리드가 렌더링되는지 확인하기 위해 AfterViewInit 수명 주기 후크를 사용합니다. 부모가 없기 때문에 rootLeveltrue 이고 이에 대한 키만 서비스의 getData에 전달할 수 있습니다. Observable을 반환하므로 이를 구독해야 합니다.

    public ngAfterViewInit() {
        this.remoteService.getData({ parentID: null, rootLevel: true, key: "Customers" }).subscribe((data) => {
            this.hGrid.data = data;
            this.hGrid.cdr.detectChanges();
        });
    }
    

    다음으로 생성된 새 하위 그리드에 대한 데이터를 요청하는 gridCreated 메서드만 생성하면 됩니다. 이는 루트 수준 그리드 데이터를 가져오는 것과 비슷합니다. 이번에는 parentIDparentKey와 같은 추가 정보를 전달해야 합니다. rootLevel 모든 하위 항목에 대해 false 입니다.

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

    이것으로 애플리케이션 설정이 거의 완료되었습니다. 이 마지막 단계는 사용자에게 데이터가 아직 로드 중임을 알려 사용자가 그 동안 빈 그리드를 볼 필요가 없도록 하여 사용자 경험을 개선하는 것을 목표로 합니다. 이것이 바로 IgxHierarchicalGrid 그리드가 비어 있는 동안 표시될 수 있는 로딩 표시기를 지원하는 이유입니다. 새 데이터가 수신되면 로딩 표시기가 숨겨지고 데이터가 렌더링됩니다.

    로딩 표시 설정

    IgxHierarchicalGrid는 데이터가 없는 동안 isLoading 속성을 true로 설정하여 로딩 표시기를 표시할 수 있습니다. 데이터가 로드될 때까지 처음에는 루트 그리드에 대해 설정하고 새 하위 그리드를 생성할 때도 설정해야 합니다. 템플릿에서 항상 이를 true로 설정할 수 있지만, 이를 false로 설정하여 서비스가 빈 배열을 반환하는 경우 이를 숨기고 그리드에 데이터가 없음을 표시하려고 합니다.

    이 경우 hierarchical-grid-lod.component.ts의 최종 버전은 다음과 같습니다.

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

    API References

    Additional Resources

    우리 커뮤니티는 활동적이며 항상 새로운 아이디어를 환영합니다.