Angular Hierarchical Grid のリモートデータ操作
Ignite UI for Angular Hierarchical Grid は、リモート仮想化、リモート ソート、リモート フィルタリングなどのリモート データ操作をサポートします。これにより、開発者はこれらのタスクをサーバー上で実行し、生成されたデータを取得して Hierarchical Grid に表示できます。
デフォルトで、Hierarchical Grid は独自のロジックを使用してデータ操作を実行します。
これらのタスクをリモートで実行し、Hierarchical Grid で公開される特定の入力とイベントを使用して Hierarchical Grid に結果のデータを供給できます。
一意の列値ストラテジ
Excel スタイル フィルタリング ダイアログ内のリスト項目は、それぞれの列の一意の値を表します。Hierarchical Grid は、デフォルトでデータソースに基づいてこれらの値を生成します。リモート フィルタリングの場合、グリッドのデータにはサーバーからのすべてのデータが含まれていません。これらの一意の値を手動で提供し、オンデマンドで読み込むために、Hierarchical Grid の uniqueColumnValuesStrategy
入力を利用できます。この入力は、実際には 3 つの引数を提供するメソッドです。
column - フィルタリング式ツリー。各列に基づいて削減されます。
filteringExpressionsTree - フィルタリング式ツリー。各列に基づいて削減されます。
done - サーバーから取得されたときに、新しく生成された列値で呼び出されるコールバック。
開発者は、列 と filteringExpressionsTree 引数によって提供される情報に基づいて、必要な一意の列値を手動で生成し、done コールバックを呼び出すことができます。
<igx-hierarchical-grid #hierarchicalGrid [primaryKey ]="'Artist'" [data ]="data" [filterMode ]="'excelStyleFilter'"
[uniqueColumnValuesStrategy ]="singersColumnValuesStrategy" >
...
<igx-row-island [primaryKey ]="'Album'" [allowFiltering ]="true" [filterMode ]="'excelStyleFilter'"
[uniqueColumnValuesStrategy ]="albumsColumnValuesStrategy" >
...
</igx-row-island >
</igx-hierarchical-grid >
html
public singersColumnValuesStrategy = (column: ColumnType,
columnExprTree: IFilteringExpressionsTree,
done: (uniqueValues: any []) => void ) => {
this .remoteValuesService.getColumnData(
null , 'Singers' , column, columnExprTree, uniqueValues => done(uniqueValues));
}
public albumsColumnValuesStrategy = (column: ColumnType,
columnExprTree: IFilteringExpressionsTree,
done: (uniqueValues: any []) => void ) => {
const parentRowId = (column.grid as any ).foreignKey;
this .remoteValuesService.getColumnData(
parentRowId, 'Albums' , column, columnExprTree, uniqueValues => done(uniqueValues));
}
typescript
一意の列値ストラテジのデモ
このサンプルが気に入りましたか? 完全な Ignite UI for Angularツールキットにアクセスして、すばやく独自のアプリの作成を開始します。無料でダウンロードできます。
Excel スタイル フィルタリングのカスタム ロード テンプレートを提供するには、igxExcelStyleLoading
ディレクティブを使用できます。
<igx-hierarchical-grid [data ]="data" [filterMode ]="'excelStyleFilter'" [uniqueColumnValuesStrategy ]="columnValuesStrategy" >
...
<ng-template igxExcelStyleLoading >
Loading ...
</ng-template >
</igx-hierarchical-grid >
html
リモート ページング
はじめにデータ フェッチングを行うサービスを宣言します。デフォルトのページング テンプレートを使用する場合、totalRecords
プロパティを設定する必要があります。それにより、グリッドは合計リモート レコードに基づいて合計ページ番号を計算できます。注: リモート サービスからフェッチ データを実装する必要があります。ページ カウントを計算するためにすべてのデータ項目のカウントをが必要なため、ロジックをサービスに追加する必要があります。
@Injectable ()
export class RemotePagingService {
public remoteData: BehaviorSubject<any []>;
public dataLenght: BehaviorSubject<number > = new BehaviorSubject(0 );
public url = 'https://www.igniteui.com/api/products' ;
constructor (private http: HttpClient ) {
this .remoteData = new BehaviorSubject([]) as any ;
}
public getData(index?: number , perPage?: number ): any {
let qS = '' ;
if (perPage) {
qS = `?$skip=${index} &$top=${perPage} &$count=true` ;
}
this .http
.get(`${this .url + qS} ` ).pipe(
map((data: any ) => data)
).subscribe((data ) => this .remoteData.next(data));
}
public getDataLength(): any {
return this .http.get(this .url).pipe(
map((data: any ) => data.length)
);
}
}
typescript
サービスを宣言した後にコンポーネントを作成する必要があり、Hierarchical Grid コンストラクションとデータ サブスクリプションを処理します。
export class HGridRemotePagingSampleComponent implements OnInit , AfterViewInit , OnDestroy {
public data: BehaviorSubject<any > = new BehaviorSubject([]);
private _dataLengthSubscriber;
constructor (private remoteService: RemotePagingService ) {}
public ngOnInit ( ) {
this .data = this .remoteService.remoteData.asObservable();
this ._dataLengthSubscriber = this .remoteService.getDataLength().subscribe((data ) => {
this .totalCount = data;
this .grid1.isLoading = false ;
});
}
public ngOnDestroy ( ) {
if (this ._dataLengthSubscriber) {
this ._dataLengthSubscriber.unsubscribe();
}
}
}
typescript
これで、独自のカスタム ページング テンプレートを設定するか、igx-paginator
が提供するデフォルトのテンプレートを使用するかを選択できます。まず、デフォルトのページング テンプレートを使用してリモート ページングを設定するために必要なものを見てみましょう。
デフォルト テンプレートのリモート ページング
デフォルトのページング テンプレートを使用する場合、totalRecords
プロパティを設定する必要があります。それにより、グリッドはリモートの合計レコード数に基づいて合計ページ番号を計算できます。リモート ページネーションを実行する場合、グリッドに現在のページのデータのみを渡すため、グリッドは提供されたデータソースのページネーションを試行しません。そのため、pagingMode
プロパティを GridPagingMode.remote に設定する必要があります。リモート サービスからデータをフェッチするために pagingDone
または perPageChange
イベントにサブスクライブする必要があります。イベントが使用されるユース ケースによって異なります。
<igx-hierarchical-grid #hierarchicalGrid [primaryKey ]="'CustomerID'" [pagingMode ]="mode" >
<igx-column field ="CustomerID" > </igx-column >
...
<igx-paginator [(page )]="page" [(perPage )]="perPage" [totalRecords ]="totalCount"
(pagingDone )="paginate($event.current)" (perPageChange )="getFirstPage()" >
</igx-paginator >
</igx-hierarchical-grid >
html
public totalCount = 0 ;
public data: Observable<any []>;
public mode = GridPagingMode.remote;
public isLoading = true ;
@ViewChild ('grid1' , { static : true }) public grid1: IgxGridComponent;
private _dataLengthSubscriber;
public set perPage (val: number ) {
this ._perPage = val;
this .paginate(0 );
}
public ngOnInit ( ) {
this .data = this .remoteService.remoteData.asObservable();
this ._dataLengthSubscriber = this .remoteService.getDataLength().subscribe((data: any ) => {
this .totalCount = data;
this .grid1.isLoading = false ;
});
}
public ngAfterViewInit ( ) {
const skip = this .page * this .perPage;
this .remoteService.getData(skip, this .perPage);
}
public paginate (page: number ) {
this .page = page;
const skip = this .page * this .perPage;
const top = this .perPage;
this .remoteService.getData(skip, top);
}
typescript
import { NgModule } from "@angular/core" ;
import { FormsModule } from "@angular/forms" ;
import { BrowserModule } from "@angular/platform-browser" ;
import { BrowserAnimationsModule } from "@angular/platform-browser/animations" ;
import { AppComponent } from "./app.component" ;
import { IgxHierarchicalGridModule } from "igniteui-angular" ;
import { HGridRemotePagingDefaultTemplateComponent } from "./hierarchical-grid/hierarchical-grid-remote-paging-default-template/hierarchical-grid-remote-paging-default-template.component" ;
import { HttpClientModule } from "@angular/common/http" ;
import { IgxPreventDocumentScrollModule } from "./directives/prevent-scroll.directive" ;
@NgModule ({
bootstrap : [AppComponent],
declarations : [
AppComponent,
HGridRemotePagingDefaultTemplateComponent
],
imports : [
BrowserModule,
BrowserAnimationsModule,
FormsModule,
IgxPreventDocumentScrollModule,
IgxHierarchicalGridModule,
HttpClientModule
],
providers : [],
entryComponents : [],
schemas : []
})
export class AppModule {}
ts コピー import { AfterViewInit, Component, OnDestroy, OnInit, ViewChild } from '@angular/core' ;
import { GridPagingMode, IGridCreatedEventArgs, IgxHierarchicalGridComponent } from 'igniteui-angular' ;
import { RemotePagingService } from './remotePagingService' ;
@Component ({
providers : [RemotePagingService],
selector : 'app-hierarchical-grid-remote-paging-default-template' ,
styleUrls : ['./hierarchical-grid-remote-paging-default-template.component.scss' ],
templateUrl : 'hierarchical-grid-remote-paging-default-template.component.html'
})
export class HGridRemotePagingDefaultTemplateComponent implements OnInit , AfterViewInit , OnDestroy {
@ViewChild ('hierarchicalGrid' , { static : true }) public hierarchicalGrid: IgxHierarchicalGridComponent;
public totalCount = 0 ;
public mode = GridPagingMode.Remote;
private _dataLengthSubscriber;
constructor (private remoteService: RemotePagingService ) { }
public ngOnInit(): void {
this ._dataLengthSubscriber = this .remoteService.getDataLength(
{ parentID : null , rootLevel : true , key : 'Customers' }).subscribe((length ) => {
this .totalCount = length;
});
}
public ngOnDestroy ( ) {
if (this ._dataLengthSubscriber) {
this ._dataLengthSubscriber.unsubscribe();
}
}
public ngAfterViewInit ( ) {
this .hierarchicalGrid.isLoading = true ;
this .remoteService.getData(
{ parentID : null , rootLevel : true , key : 'Customers' }, this .hierarchicalGrid.perPage)
.subscribe((data ) => {
this .hierarchicalGrid.isLoading = false ;
this .hierarchicalGrid.data = data;
},
(error ) => {
this .hierarchicalGrid.emptyGridMessage = error.message;
this .hierarchicalGrid.isLoading = false ;
this .hierarchicalGrid.cdr.detectChanges();
}
);
}
public dateFormatter (val: string ) {
return new Intl .DateTimeFormat('en-US' ).format(new Date (val));
}
public gridCreated (event: IGridCreatedEventArgs, _foreignKey: string ) {
const dataState = {
foreignKey : _foreignKey,
key : event.owner.key,
parentID : event.parentID,
rootLevel : false
};
event.grid.isLoading = true ;
this .remoteService.getData(dataState).subscribe(
(data ) => {
event.grid.isLoading = false ;
event.grid.data = data;
event.grid.cdr.detectChanges();
},
(error ) => {
event.grid.emptyGridMessage = error.message;
event.grid.isLoading = false ;
event.grid.cdr.detectChanges();
}
);
}
public pagingDone (page ) {
const skip = page.current * this .hierarchicalGrid.perPage;
this .remoteService.getData(
{ parentID : null , rootLevel : true , key : 'Customers' }, skip, this .hierarchicalGrid.perPage)
.subscribe((data ) => {
this .hierarchicalGrid.data = data;
this .hierarchicalGrid.cdr.detectChanges();
},
(error ) => {
this .hierarchicalGrid.emptyGridMessage = error.message;
this .hierarchicalGrid.data = null ;
this .hierarchicalGrid.cdr.detectChanges();
}
);
}
public getFirstPage ( ) {
this .remoteService.getData(
{ parentID : null , rootLevel : true , key : 'Customers' }, 0 , this .hierarchicalGrid.perPage)
.subscribe((data ) => {
this .hierarchicalGrid.data = data;
this .hierarchicalGrid.cdr.detectChanges();
});
}
}
ts コピー <div class ="grid__wrapper" >
<igx-hierarchical-grid [igxPreventDocumentScroll ]="true" [primaryKey ]="'CustomerID'"
[height ]="'550px'" [width ]="'100%'" [pagingMode ]="mode" #hierarchicalGrid >
<igx-paginator
[totalRecords ]="totalCount"
(pagingDone )="pagingDone($event)"
(perPageChange )="getFirstPage()" >
</igx-paginator >
<igx-column field ="CustomerID" > </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 [height ]="null" [key ]="'Orders'" [primaryKey ]="'OrderID'" [autoGenerate ]="false"
(gridCreated )="gridCreated($event, 'CustomerID')" >
<igx-paginator *igxPaginator [perPage ]="5" >
</igx-paginator >
<igx-column field ="OrderID" > </igx-column >
<igx-column field ="OrderDate" [formatter ]="dateFormatter" > </igx-column >
<igx-column field ="ShipCountry" > </igx-column >
<igx-column field ="ShipCity" > </igx-column >
<igx-column field ="ShipAddress" > </igx-column >
<igx-row-island [height ]="null" [key ]="'Order_Details'" [primaryKey ]="'ProductID'" [autoGenerate ]="false"
(gridCreated )="gridCreated($event, 'OrderID')" >
<igx-paginator *igxPaginator [perPage ]="5" >
</igx-paginator >
<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 >
</div >
html コピー .grid__wrapper {
margin : 0 16px ;
padding-top : 10px ;
}
scss コピー
カスタム igx-paginator-content のリモート ページング
カスタム ページネーター コンテンツを定義するときは、要求されたページのデータのみを取得するようにコンテンツを定義し、選択したページと perPage
項目に応じて正しい skip および top パラメーターをリモート サービスに渡す必要があります。導入された IgxPageSizeSelectorComponent
と IgxPageNavigationComponent
とともに、設定例を簡単にするために <igx-paginator>
を使用します。igx-page-size
はページごとのドロップダウンとラベルを追加し、igx-page-nav
はナビゲーション アクション ボタンとラベルを追加します。
<igx-paginator #paginator
[totalRecords ]="totalCount"
[(perPage )]="perPage"
[(page )]="page"
[selectOptions ]="selectOptions"
(pageChange )="paginate($event)"
(perPageChange )="perPageChange($event)" >
<igx-paginator-content >
<igx-page-size > </igx-page-size >
[This is my custom content]
<igx-page-nav > </igx-page-nav >
</igx-paginator-content >
</igx-paginator >
html
@ViewChild ('hierarchicalGrid' , { static : true }) public hierarchicalGrid: IgxHierarchicalGridComponent;
public ngOnInit(): void {
this ._dataLengthSubscriber = this .remoteService.getDataLength(
{ parentID : null , rootLevel : true , key : 'Customers' }).subscribe((length ) => {
this .totalCount = length;
});
}
public ngAfterViewInit ( ) {
this .hierarchicalGrid.isLoading = true ;
this ._dataSubscriber = this .remoteService.getData({parentID : null , rootLevel : true , key : 'Customers' }, 0 , this .perPage)
.subscribe((data ) => {
this .hierarchicalGrid.isLoading = false ;
this .data.next(data);
},(error ) => {
this .hierarchicalGrid.emptyGridMessage = error.message;
this .hierarchicalGrid.isLoading = false ;
this .hierarchicalGrid.cdr.detectChanges();
}
);
}
typescript
リモート ページングを適切に構成するには、GridPagingMode.Remote
を設定する必要があります。
<igx-hierarchical-grid #hierarchicalGrid [data ]="data | async" [primaryKey ]="'CustomerID'"
[height ]="'550px'" [width ]="'100%'" [pagingMode ]="mode" > </igx-hierarchical-grid >
...
public mode = GridPagingMode.Remote;
html
最後の手順は、要件に基づいてページネーターのコンテンツを宣言することです。
<igx-paginator-content >
<igx-page-size > </igx-page-size >
[This is my custom content]
<igx-page-nav > </igx-page-nav >
</igx-paginator-content >
html
上記すべての設定を完了すると以下のような結果になります。
import { NgModule } from "@angular/core" ;
import { FormsModule } from "@angular/forms" ;
import { BrowserModule } from "@angular/platform-browser" ;
import { BrowserAnimationsModule } from "@angular/platform-browser/animations" ;
import { AppComponent } from "./app.component" ;
import {
IgxHierarchicalGridModule,
IgxSelectModule
} from "igniteui-angular" ;
import { HGridRemotePagingSampleComponent } from "./hierarchical-grid/hierarchical-grid-paging/hierarchical-grid-remote-paging.component" ;
import { HttpClientModule } from "@angular/common/http" ;
import { IgxPreventDocumentScrollModule } from "./directives/prevent-scroll.directive" ;
@NgModule ({
bootstrap : [AppComponent],
declarations : [
AppComponent,
HGridRemotePagingSampleComponent
],
imports : [
BrowserModule,
BrowserAnimationsModule,
FormsModule,
IgxPreventDocumentScrollModule,
IgxHierarchicalGridModule,
HttpClientModule,
IgxSelectModule
],
providers : [],
entryComponents : [],
schemas : []
})
export class AppModule {}
ts コピー import { AfterViewInit, Component, OnDestroy, OnInit, TemplateRef, ViewChild } from '@angular/core' ;
import { GridPagingMode, IGridCreatedEventArgs, IgxHierarchicalGridComponent, IgxRowIslandComponent } from 'igniteui-angular' ;
import { RemotePagingService } from './remotePagingService' ;
import { BehaviorSubject } from 'rxjs' ;
@Component ({
providers : [RemotePagingService],
selector : 'app-hierarchical-grid-remote-paging' ,
styleUrls : ['./hierarchical-grid-remote-paging.component.scss' ],
templateUrl : 'hierarchical-grid-remote-paging.component.html'
})
export class HGridRemotePagingSampleComponent implements OnInit , AfterViewInit , OnDestroy {
@ViewChild ('hierarchicalGrid' , { static : true }) public hierarchicalGrid: IgxHierarchicalGridComponent;
public page = 0 ;
public lastPage = false ;
public firstPage = true ;
public totalCount = 0 ;
public title = 'gridPaging' ;
public selectOptions = [5 , 10 , 25 , 50 ];
public data: BehaviorSubject<any > = new BehaviorSubject([]);
public mode = GridPagingMode.Remote;
private _perPage = 10 ;
private _dataLengthSubscriber;
private _dataSubscriber;
constructor (private remoteService: RemotePagingService ) { }
public ngOnInit(): void {
this ._dataLengthSubscriber = this .remoteService.getDataLength(
{ parentID : null , rootLevel : true , key : 'Customers' }).subscribe((length ) => {
this .totalCount = length;
});
}
public ngOnDestroy ( ) {
if (this ._dataLengthSubscriber) {
this ._dataLengthSubscriber.unsubscribe();
}
if (this ._dataSubscriber) {
this ._dataSubscriber.unsubscribe();
}
}
public ngAfterViewInit ( ) {
this .hierarchicalGrid.isLoading = true ;
this ._dataSubscriber = this .remoteService.getData({parentID : null , rootLevel : true , key : 'Customers' }, 0 , this .perPage)
.subscribe((data ) => {
this .hierarchicalGrid.isLoading = false ;
this .data.next(data);
},(error ) => {
this .hierarchicalGrid.emptyGridMessage = error.message;
this .hierarchicalGrid.isLoading = false ;
this .hierarchicalGrid.cdr.detectChanges();
}
);
}
public get perPage (): number {
return this ._perPage;
}
public set perPage (val: number ) {
this ._perPage = val;
this .paginate(0 );
}
public dateFormatter (val: string ) {
return new Intl .DateTimeFormat('en-US' ).format(new Date (val));
}
public gridCreated (event: IGridCreatedEventArgs, _foreignKey: string ) {
const dataState = {
foreignKey : _foreignKey,
key : event.owner.key,
parentID : event.parentID,
rootLevel : false
};
event.grid.isLoading = true ;
this .remoteService.getData(dataState).subscribe(
(data ) => {
event.grid.isLoading = false ;
event.grid.data = data;
event.grid.cdr.detectChanges();
},
(error ) => {
event.grid.emptyGridMessage = error.message;
event.grid.isLoading = false ;
event.grid.cdr.detectChanges();
}
);
}
public paginate (page: number ) {
this .page = page;
const skip = this .page * this .perPage;
const top = this .perPage;
this .remoteService.getData(
{ parentID : null , rootLevel : true , key : 'Customers' }, skip, top).subscribe((data ) => {
this .data.next(data);
this .hierarchicalGrid.cdr.detectChanges();
},
(error ) => {
this .hierarchicalGrid.emptyGridMessage = error.message;
this .data.next([]);
this .hierarchicalGrid.cdr.detectChanges();
}
);
}
public perPageChange (perPage: number ) {
const skip = this .page * perPage;
const top = perPage;
this .remoteService.getData(skip, top);
}
}
ts コピー <div class ="grid__wrapper" >
<igx-hierarchical-grid [igxPreventDocumentScroll ]="true" [data ]="data | async" [primaryKey ]="'CustomerID'" [height ]="'550px'" [width ]="'100%'" #hierarchicalGrid
[pagingMode ]="mode" >
<igx-column field ="CustomerID" > </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 [height ]="null" [key ]="'Orders'" [primaryKey ]="'OrderID'" [autoGenerate ]="false"
(gridCreated )="gridCreated($event, 'CustomerID')" >
<igx-paginator *igxPaginator [perPage ]="5" > </igx-paginator >
<igx-column field ="OrderID" > </igx-column >
<igx-column field ="OrderDate" [formatter ]="dateFormatter" > </igx-column >
<igx-column field ="ShipCountry" > </igx-column >
<igx-column field ="ShipCity" > </igx-column >
<igx-column field ="ShipAddress" > </igx-column >
<igx-row-island [height ]="null" [key ]="'Order_Details'" [primaryKey ]="'ProductID'" [autoGenerate ]="false"
(gridCreated )="gridCreated($event, 'OrderID')" >
<igx-paginator *igxPaginator [perPage ]="5" > </igx-paginator >
<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-paginator #paginator
[totalRecords ]="totalCount"
[(perPage )]="perPage"
[(page )]="page"
[selectOptions ]="selectOptions"
(pageChange )="paginate($event)"
(perPageChange )="perPageChange($event)" >
<igx-paginator-content >
<igx-page-size > </igx-page-size >
[This is my custom content]
<igx-page-nav > </igx-page-nav >
</igx-paginator-content >
</igx-paginator >
</igx-hierarchical-grid >
</div >
html コピー .grid__wrapper {
margin : 0 16px ;
padding-top : 10px ;
}
scss コピー
既知の問題と制限
グリッドに primaryKey
が設定されておらず、リモート データ シナリオが有効になっている場合 (ページング、ソート、フィルタリング、スクロール時に、グリッドに表示されるデータを取得するためのリモート サーバーへのリクエストがトリガーされる場合)、データ要求が完了すると、行は次の状態を失います:
リモート データ シナリオでは、グリッドに primaryKey
が設定されている場合、rowSelectionChanging.oldSelection
イベント引数には、現在データ ビューに含まれていない行の完全な行データ オブジェクトが含まれません。この場合、rowSelectionChanging.oldSelection
オブジェクトには、primaryKey
フィールドである 1 つのプロパティのみが含まれます。現在データ ビューにある残りの行については、rowSelectionChanging.oldSelection
に行データ全体が含まれます。
API リファレンス
その他のリソース
コミュニティに参加して新しいアイデアをご提案ください。