仮想ドロップダウン
Ignite UI for Angular Drop Down コンポーネントは、選択可能な項目の非常に大きなリストを表示するために Virtual Scroll コンポーネントと組み合わせて使用できます。ドロップダウンのビューポート内の項目のみがレンダリングされ、選択とキーボード ナビゲーションはリスト全体に対して機能します。
Angular 仮想ドロップダウンの例
使用方法
はじめに
VirtualScroll と、リスト項目のテンプレートをマークする IgxVirtualItemDirective をドロップダウンと一緒にインポートします。
// drop-down-virtual.component.ts
import { Component } from '@angular/core';
import { IgxButtonDirective, IgxToggleActionDirective } from 'igniteui-angular/directives';
import { IgxDropDownComponent, IgxDropDownItemComponent, IgxDropDownItemNavigationDirective } from 'igniteui-angular/drop-down';
import { IgxVirtualItemDirective, IgxVirtualScrollComponent } from 'igniteui-angular/virtual-scroll';
// import { IgxVirtualItemDirective, IgxVirtualScrollComponent } from '@infragistics/igniteui-angular'; for licensed package
@Component({
selector: 'app-drop-down-virtual',
templateUrl: './drop-down-virtual.component.html',
styleUrls: ['./drop-down-virtual.component.scss'],
imports: [
IgxButtonDirective, IgxToggleActionDirective, IgxDropDownItemNavigationDirective,
IgxDropDownComponent, IgxDropDownItemComponent,
IgxVirtualScrollComponent, IgxVirtualItemDirective
]
})
export class DropDownVirtualComponent { }
テンプレートの構成
次に、ドロップダウンの内側に igx-virtual-scroll を配置し、igxVirtualItem でマークされた ng-template で各項目をレンダリングします。ドロップダウンは投影された Virtual Scroll を検出し、スクロール、キーボード ナビゲーション、選択にそれを使用します。
<!-- drop-down-virtual.component.html -->
<button igxButton [igxToggleAction]="dropdown" [igxDropDownItemNavigation]="dropdown">
Item Series
</button>
<igx-drop-down #dropdown>
<igx-virtual-scroll class="drop-down-virtual-wrapper" [data]="items" [estimatedItemSize]="itemHeight">
<ng-template igxVirtualItem let-item let-index="index">
<igx-drop-down-item [value]="item" [isHeader]="item.header" [disabled]="item.disabled" [index]="index">
{{ item.name }}
</igx-drop-down-item>
</ng-template>
</igx-virtual-scroll>
</igx-drop-down>
<div>Selected Model: <span>{{ dropdown.selectedItem?.value.name }}</span></div>
ここで使用されている igx-virtual-scroll の入力は次のとおりです。
data- 項目全体のリスト。参照によって比較されるため、変更するには新しい配列を割り当てます。estimatedItemSize- レンダリングされて測定される前の項目の高さ (px単位)。スクロールバーとキーボード ナビゲーションが最初から正確になるように、ドロップダウン項目の実際の高さに設定します。
項目の一意性を確保するために、igx-drop-down-item の value 入力に item を、index 入力に index を渡します。
スクロール時にも選択状態を維持するには、ドロップダウン項目はそれがバインドされているデータ項目への参照を持つ必要があります。
各項目に対して [value] 入力に一意の値を渡すことを強くお勧めします。渡さない場合、予想外の結果 (誤った選択) になる可能性があります。
ドロップダウンが仮想化された項目を使用する場合、dropdown.selectedItem の型は { value: any, index: number } になります。ここで、value は [value] 入力に渡されたデータ項目への参照であり、index はデータセット内の項目のインデックスです。
コンポーネント定義
コンポーネントの内部で、ドロップダウンに表示される、適度に大きな項目のリスト (ヘッダーと無効な項目の両方を含む) と、項目の高さを宣言します。
// drop-down-virtual.component.ts
export class DropDownVirtualComponent {
public items: DataItem[];
public itemHeight = 40;
constructor() {
const itemsCollection: DataItem[] = [];
for (let i = 0; i < 50; i++) {
const series = (i * 10).toString();
itemsCollection.push({
id: series,
name: `${series} Series`,
header: true,
disabled: false
});
for (let j = 0; j < 10; j++) {
itemsCollection.push({
id: `${series}_${j}`,
name: `Series ${series}, ${i * 10 + j} Model`,
header: false,
disabled: j % 9 === 0
});
}
}
this.items = itemsCollection;
}
}
スタイル
igx-virtual-scroll 要素はリストのスクロール コンテナーであるため、固定の高さが必要です。ラッピング要素や overflow ルールは必要ありません。
// drop-down-virtual.component.scss
.drop-down-virtual-wrapper {
height: 240px;
width: 180px;
}
リモート データ
igx-drop-down は、リモート データのページの読み込みもサポートしています。Virtual Scroll の dataWindow 入力を読み込まれたページにバインドし、stateChange 出力が報告する範囲から次のページを読み込みます。リストはリモート コレクション全体と同じ長さになるため、スクロールバーはすべての項目にまたがりますが、読み込まれたページのみがメモリー内にあります。
テンプレート
このテンプレートは、データ バインディングの点でのみ前の例と異なります。dataWindow が data の代わりとなり、stateChange がページを要求します。index テンプレート変数は、リモート コレクション全体における項目のインデックスです。
<igx-drop-down #remoteDropDown>
<igx-virtual-scroll
class="drop-down-virtual-wrapper"
[dataWindow]="page()"
[estimatedItemSize]="itemHeight"
(stateChange)="onStateChange($event)">
<ng-template igxVirtualItem let-item let-index="index">
<igx-drop-down-item [value]="item.ProductName" [index]="index">
{{ item.ProductName }}
</igx-drop-down-item>
</ng-template>
</igx-virtual-scroll>
</igx-drop-down>
ページの読み込み
まず、コレクションのページとレコードの総数を返すリモート サービスを定義します。
// remote.service.ts
import { HttpClient } from '@angular/common/http';
import { Injectable, inject } from '@angular/core';
import { Observable } from 'rxjs';
@Injectable()
export class RemoteService {
private http = inject(HttpClient);
// Assuming that the API service is RESTful and can take the following:
// skip: start index of the data that we fetch
// count: number of records we fetch
public getPage(skip: number, count: number): Observable<{ value: any[]; '@odata.count': number }> {
return this.http.get<{ value: any[]; '@odata.count': number }>(
`https://dummy.db/dummyEndpoint?$skip=${skip}&$top=${count}&$count=true`
);
}
}
コンポーネントでは、読み込まれたページを VirtualDataWindow 型のシグナルに保持します。初期化時に最初のページを読み込み、stateChange が読み込み済みのページがカバーしていない範囲を報告するたびに新しいページを読み込みます。以前のリクエストをキャンセルすることで、遅い応答が新しいページを上書きしないようにします。
// drop-down-remote.component.ts
import { Component, OnDestroy, OnInit, inject, signal } from '@angular/core';
import { VirtualDataWindow, VirtualScrollState } from 'igniteui-angular/virtual-scroll';
import { Subscription } from 'rxjs';
/** Extra records requested on each side of the range the viewport wants. */
const BUFFER = 10;
@Component({
providers: [RemoteService],
selector: 'app-drop-down-remote',
templateUrl: './drop-down-remote.component.html',
styleUrls: ['./drop-down-remote.component.scss'],
imports: [/* the same imports as in the local example */]
})
export class DropDownRemoteComponent implements OnInit, OnDestroy {
private remoteService = inject(RemoteService);
public itemHeight = 40;
public readonly page = signal<VirtualDataWindow<any>>({ items: [], startIndex: 0, totalCount: 0 });
private pending?: Subscription;
public ngOnInit() {
this.loadPage(0, 2 * BUFFER);
}
public onStateChange(state: VirtualScrollState) {
const page = this.page();
if (state.startIndex >= page.startIndex && state.endIndex < page.startIndex + page.items.length) {
return; // The loaded page already covers the range.
}
const startIndex = Math.max(0, state.startIndex - BUFFER);
this.loadPage(startIndex, state.endIndex - startIndex + 1 + BUFFER);
}
public ngOnDestroy() {
this.pending?.unsubscribe();
}
private loadPage(startIndex: number, count: number) {
this.pending?.unsubscribe();
this.pending = this.remoteService.getPage(startIndex, count).subscribe(data => {
this.page.set({ items: data.value, startIndex, totalCount: data['@odata.count'] });
});
}
}
ドロップダウンが、例えば End キーでまだ読み込まれていない項目にナビゲートすると、Virtual Scroll はその項目までスクロールし、stateChange が新しい範囲を報告し、その項目を含むページが読み込まれます。
リモートの仮想化 - デモ
上記の設定の結果は、スクロールバーの状態に応じて、表示するデータを動的に読み込むドロップダウンです。
注意と制限
仮想化された項目のリストでドロップダウンを使用すると、いくつかの制限があります。igx-virtual-scroll を使用してドロップダウン リストを設定するときは、次の点に注意してください。
igx-virtual-scroll要素はリストのスクロール コンテナーであるため、固定のheightを持つ必要があります。- リストが仮想化されている場合、
<igx-drop-down-item-group>を項目のグループ化に使用することはできません。代わりにisHeaderプロパティを使用します。 itemsアクセサーは、現在仮想化ビューにあるヘッダー以外のドロップダウン項目のリストのみを返します。dropdown.selectedItemの型は{ value: any, index: number }です。selectionChangingによって発行されるオブジェクトは、const emittedEvent: { newSelection: { value: any, index: number }, oldSelection: { value: any, index: number }, cancel: boolean, }に変わります。dropdown.setSelectedItemは、データセット内の項目のインデックスを使用して呼び出す必要があります。- ドロップダウン項目の
[selected]入力を設定しても、ドロップダウンの選択内で項目がマークされることはありません。
ドロップダウンは、以前のバージョンと同様に、投影された *igxFor ディレクティブでも動作します。このディレクティブは非推奨となり、Virtual Scroll に置き換えられているため、新しいドロップダウンには igx-virtual-scroll を使用してください。