Close
Angular React Web Components Blazor
Open Source

仮想ドロップダウン

Ignite UI for Angular Drop Down コンポーネントは、選択可能な項目リストを表示するために、IgxForOf ディレクティブの使用方法を完全に統合できます。

Angular 仮想ドロップダウンの例


使用方法

はじめに

仮想アイテムのリストを表示するようにドロップダウンを設定するには、いくつかの前提条件を満たす必要があります。 はじめにドロップダウンを宣言するコンポーネントのモジュールに IgxForOfModule をインポートする必要があります。

// app.module.ts
import { IgxForOfModule } from 'igniteui-angular/directives';
// import { IgxForOfModule } from '@infragistics/igniteui-angular'; for licensed package

@NgModule({
    imports: [
        ...
        IgxForOfModule
    ]
})
export class AppModule {}

テンプレートの構成

次に、*ngFor の代わりに *igxFor を使用してデータをループ処理し、ドロップダウン コンポーネントのテンプレートを作成する必要があります。*igxFor ディレクティブは、すべての項目を正しく表示するために追加の構成が必要です。

<!-- drop-down-virtual.component.html -->
<button igxButton [igxToggleAction]="dropdown"
        [igxDropDownItemNavigation]="dropdown">
        Item Series
</button>
<igx-drop-down #dropdown>
    <div class="drop-down-virtual-wrapper" style="height: {{ itemsMaxHeight }}px;">
        <igx-drop-down-item
            *igxFor="let item of items; index as index;
                     scrollOrientation: 'vertical';
                     containerSize: itemsMaxHeight;
                     itemSize: itemHeight;"
            [value]="item" [isHeader]="item.header"
            role="option" [disabled]="item.disabled"
            [index]="index">
            {{ item.name }}
        </igx-drop-down-item>
    </div>
</igx-drop-down>
<div>Selected Model: <span>{{ dropdown.selectedItem?.value.name }}</span></div>

以下は、*igxFor ディレクティブに渡される追加パラメーターです。

  • index - データセット内の現在の項目のインデックスを取得します。
  • scrollOrientation - 常に 'vertical' にする必要があります。
  • containerSize - 仮想化コンテナーのサイズ (ピクセル単位)。これは、ラッピング <div> にも適用する必要があります。
  • itemSize - 表示される項目のサイズ (ピクセル単位)。

項目の一意性を確保するために、value input の内の item および igx-drop-down-itemindex 内の index を渡します。 スクロールしながら選択を維持するには、ドロップダウン 項目はそれがバインドされているデータ項目への参照を持つ必要があります。

ドロップダウンが項目の仮想化リストで機能するためには、value および index の入力をすべての項目に渡す必要があります。

各項目に対して [value] 入力に渡される一意の値を持たない場合、予想外の結果 (誤った選択) となる場合があります。

ドロップダウンが仮想化項目を使用する場合、dropdown.selectedItem の種類は { value: any, index: number } になります。ここで、value はデータ項目への参照です。[value] input の内に渡され、index はデータセット内の項目のインデックスです。

コンポーネント定義

コンポーネントの constructor 内で、ドロップダウンに表示される、適度に大きな項目のリスト (ヘッダーと無効なアイテムの両方を含む) を宣言します。itemHeightitemsMaxHeight を宣言する必要があります。

// drop-drop-virtual.component.ts
export class DropDownVirtualComponent {
  public items: DataItem[];
  public itemHeight = 48;
  public itemsMaxHeight = 320;

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

スタイル

最後に、ラッピング div に overflow: hidden を設定して、2 つのスクロールバー (igxFor のスクロールバーとコンテナー自体のスクロールバー) が表示されないようにします。

// drop-drop-virtual.component.scss
.drop-down-virtual-wrapper {
  overflow: hidden;
}

リモート データ

igx-drop-down は、*igxFor 構造ディレクティブを使用したリモート データの部分的な読み込みをサポートします。構成はローカル項目の構成に似ていますが、主な違いはデータ部分の読み込み方法です。

テンプレート

ドロップダウン テンプレートは、以前の例 と比べてそれほど変更する必要はありません。それでも、ラッピング div を指定し、それに応じてスタイルを設定し、*igxFor の完全な設定を書き出す必要があります。リモートソースからデータを取得するので、データが観測可能になるように指定して Angular の async パイプに渡す必要があります。

<igx-drop-down #remoteDropDown>
    <div class="drop-down-virtual-wrapper">
        <igx-drop-down-item
            *igxFor="let item of rData | async; index as index;
                     scrollOrientation: 'vertical';
                     containerSize: itemsMaxHeight;
                     itemSize: itemHeight;"
            [value]="item.ProductName" role="option"
            [disabled]="item.disabled" [index]="index">
            {{ item.ProductName }}
        </igx-drop-down-item>
    </div>
</igx-drop-down>

チャンクロードの処理

ご覧のとおり、テンプレートは前の例のテンプレートとほとんど同じです。このリモートデータのシナリオでは、背後にあるコードが大部分の負担を軽減します。

まず、データを取得するためのリモートサービスを定義する必要があります。

// remote.service.ts
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { IForOfState } from 'igniteui-angular/directives';
// import { IForOfState } from '@infragistics/igniteui-angular'; for licensed package
import { BehaviorSubject, Observable } from 'rxjs';

@Injectable()
export class RemoteService {
    public remoteData: Observable<any[]>;
    private _remoteData: BehaviorSubject<any[]>;

    constructor(private http: HttpClient) {
        this._remoteData = new BehaviorSubject([]);
        this.remoteData = this._remoteData.asObservable();
    }

    public getData(data?: IForOfState, cb?: (any) => void): any {
        // Assuming that the API service is RESTful and can take the following:
        // skip: start index of the data that we fecth
        // count: number of records we fetch
    this.http.get(`https://dummy.db/dummyEndpoint?skip=${data.startIndex}&count=${data.chunkSize}`).subscribe((data) => {
        // emit the values through the _remoteData subject
        this._remoteData.next(data);
    })
}

このサービスは、remoteData の下に Observable を公開します。リモート ドロップダウン コンポーネントでサービスを注入し、そのプロパティにバインドします。

// remote-drop-down.component.ts
@Component({
    providers: [RemoteService],
    selector: 'app-drop-down-remote',
    templateUrl: './drop-down-remote.component.html',
    styleUrls: ['./drop-down-remote.component.scss']
})
export class DropDownRemoteComponent implements OnInit, OnDestroy {
    @ViewChild(IgxForOfDirective, { read: IgxForOfDirective })
    public remoteForDir: IgxForOfDirective<any>;
    @ViewChild('remoteDropDown', { read: IgxDropDownComponent })
    public remoteDropDown: IgxDropDownComponent;
    public itemHeight = 48;
    public itemsMaxHeight = 480;
    public prevRequest: Subscription;
    public rData: any;

    private destroy$ = new Subject();
    constructor(private remoteService: RemoteService) { }

    public ngAfterViewInit() {
        const initialState = { startIndex: 0, chunkSize: Math.ceil(this.itemsMaxHeight / this.itemHeight) }
        this.remoteService.getData(initialState, (data) => {
            this.remoteForDir.totalItemCount = data['@odata.count'];
        });
        // Subscribe to igxForOf.chunkPreload and load new data from service
        this.remoteForDir.chunkPreload.pipe(takeUntil(this.destroy$)).subscribe((data) => {
            this.dataLoading(data);
        });
    }

    public dataLoading(evt) {
        if (this.prevRequest) {
            this.prevRequest.unsubscribe();
        }
        this.prevRequest = this.remoteService.getData(
            evt,
            (data) => {
                this.remoteForDir.totalItemCount = data['@odata.count'];
            });
    }

    public ngOnInit() {
        this.rData = this.remoteService.remoteData;
    }

    public ngOnDestroy() {
        this.destroy$.next();
        this.destroy$.complete();
    }
}

ngAfterViewInit フックの内部で、初期状態のデータを取得し、igxForOf ディレクティブの chunkPreload エミッターをサブスクライブするために呼び出します。このサブスクリプションは、ロードされたチャンクが変更されるたびにデータを取得します。コンポーネントの破棄時にエミッターから簡単にサブスクライブ解除できるように、pipe(takeUntil(this.destroy$)) を使用します。

リモートの仮想化 - デモ

上記の設定の結果は、スクロールバーの状態に応じて表示されるはずのデータを動的にロードするドロップダウンです。


注意と制限

仮想化された項目のリストでドロップダウンを使用すると、いくつかの制限があります。*igxFor を使用してドロップダウン リストを設定するときは、次の点に注意してください。

  • ループされているロップダウン項目は、次の css を持つラッピング要素 (<div> など) で渡す必要があります。overflow: hiddenheightcontainerSize に等しい (px で) 。

  • リストが仮想化されている場合、<igx-drop-down-item-group> を項目のグループ化に使用することはできません。代わりに isHeader プロパティを使用します。

  • items アクセサーは、現在仮想化ビューにあるヘッダー以外のロップダウン項目のリストのみを返します。

  • dropdown.selectedItem は、タイプ { value: any, index: number } です。

  • selection によって発行されたオブジェクトは、const emittedEvent: { newSelection: { value: any, index: number }, oldSelection: { value: any, index: number }, cancel: boolean, } に変更されます。

  • dropdown.setSelectedItem は、データセット内の項目のインデックスを使用して呼び出す必要があります。

  • ドロップダウン項目の [selected] 入力を設定しても、ドロップダウン選択内の項目はマークされません。

  • The drop-down items that are being looped need to be passed in a wrapping element (e.g. <div>) which has the following css: overflow: hidden and height equal to containerSize in px

  • <igx-drop-down-item-group> cannot be used for grouping items when the list is virtualized. Use the isHeader property instead

  • The items accessor will return only the list of non-header drop-down items that are currently in the virtualized view.

  • dropdown.selectedItem is of type { value: any, index: number }

  • The object emitted by selection changes to const emittedEvent: { newSelection: { value: any, index: number }, oldSelection: { value: any, index: number }, cancel: boolean, }

  • dropdown.setSelectedItem should be called with the item’s index in the data set

  • setting the drop-down item’s [selected] input will not mark the item in the drop-down selection

API リファレンス