계층적 그리드 로드 온디맨드
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
다음으로 계층적 그리드를 설정하고 이를 원격 서비스 공급자에 연결하겠습니다.
템플릿 정의
먼저 우리가 기대하는 계층 구조 수준을 사용하여 계층적 그리드 템플릿을 정의합니다. 우리는 고객의 루트 그리드 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();
}
);
}
}