계층적 그리드 로드 온디맨드
Ignite UI for Angular IgxHierarchicalGrid
서버에서 최소한의 데이터만 검색하여 요청함으로써 빠른 렌더링을 허용하여 사용자가 결과를 뷰에서 보고 가능한 한 빨리 표시되는 데이터와 상호 작용할 수 있도록 합니다. 처음에는 루트 그리드의 데이터만 검색하여 렌더링하고, 사용자가 자식 그리드가 포함된 행을 확장한 후에만 해당 자식 그리드에 대한 데이터를 수신합니다. 이 메커니즘은 Load on Demand라고도 하며, 모든 원격 데이터와 작동하도록 쉽게 구성할 수 있습니다.
이 항목에서는 이미 사용 가능한 원격 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
더 낮은 수준의 경우. 모델은 애플리케이션마다 다르지만 다음 모델을 사용하겠습니다.
![](/products/ignite-ui-angular/angular/images/hgrid-database.jpg)
먼저 필요한 것은 원하는 그리드에 대한 데이터를 가져올 위치를 결정하기 위한 테이블의 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
다음으로 계층적 그리드를 설정하고 이를 원격 서비스 공급자에 연결하겠습니다.
템플릿 정의
먼저 우리가 기대하는 계층 구조 수준을 사용하여 계층적 그리드 템플릿을 정의합니다. 우리는 고객의 루트 그리드 primaryKey
가 CustomerID
이고, 첫 번째 수준의 주문인 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
수명 주기 후크를 사용합니다. 부모가 없기 때문에 rootLevel
이 true
이고 이에 대한 키만 서비스의 getData
에 전달할 수 있습니다. Observable을 반환하므로 이를 구독해야 합니다.
public ngAfterViewInit() {
this.remoteService.getData({ parentID: null, rootLevel: true, key: "Customers" }).subscribe((data) => {
this.hGrid.data = data;
this.hGrid.cdr.detectChanges();
});
}
다음으로 생성된 새 하위 그리드에 대한 데이터를 요청하는 gridCreated
메서드만 생성하면 됩니다. 이는 루트 수준 그리드 데이터를 가져오는 것과 비슷합니다. 이번에는 parentID
및 parentKey
와 같은 추가 정보를 전달해야 합니다. 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();
}
);
}
}