ngx-datatableのページングについて調べてみた

Angularで表を組むのに便利なライブラリと言えば、ngx-datatableです。
https://swimlane.gitbook.io/ngx-datatable/

ngx-datatableでは様々な種類のページング方法に対応しています。
公式の実装サンプルには5つ紹介されていますが、名前からはいまいち違いがわからないように感じたので、分類してみました。

|  | 実装サンプル | ページングロジック | 無限スクロール | ページ指定してデータ取得 |
|---|---|---|:-:|:-:|:-:|
| Client-side | https://swimlane.github.io/ngx-datatable/#client-paging | クライアントサイド | × | ○ |
| Server-side | https://swimlane.github.io/ngx-datatable/#server-paging | サーバサイド | × | ○ |
| Scrolling no virtual | https://swimlane.github.io/ngx-datatable/#paging-scrolling-novirtualization | サーバサイド | × | ○ |
| Scrolling server-side | https://swimlane.github.io/ngx-datatable/#server-scrolling | サーバサイド | ○ | × |
| Virtual server-side | https://swimlane.github.io/ngx-datatable/#virtual-paging | サーバサイド | ○ | ○ |

ページングのロジックがクライアントかサーバサイドかの2パターンがありますが、クライアントサイドというのは、全てのデータが入った配列をページごとに区切る処理をクライアントで行う場合です。

# datatableのプロパティ早見表
先に結論からで、
無限スクロールありなしとページ指定ありなしの組み合わせパターンに応じた、datatableの`@Input`, `@Output`の指定の仕方をまとめました。
（ややこしいのでサーバサイドの話のみに絞っています）

| `@Input` `@Output` | 説明 | 無限スクロール×　ページ指定○　（Server-side、Scrolling no virtual） | 無限スクロール○　ページ指定×（Scrolling server-side） | 無限スクロール○　ページ指定○（Virtual server-side） |
|---|---|---|---|---|
|[rows]| 表に表示するデータの配列 | 指定ページに属するデータのみ | データの全件の配列 | データの全件の配列 |
|[limit]| 1ページあたりの件数 | 指定する | 指定しない | 指定しない |
|[externalPaging]| ページングの情報をdatatable外部に持つかどうか | true | false | true |
|[count]| 全データ件数 | 指定する | 指定しない | 指定する |
|[offset]|ページ番号。0オリジンなので注意。 | 指定する | 指定しない | 指定する |
|[virtualization]|スクロールによりページングを行うかどうか | スクロールバーを出したいときは明示的にfalseを指定する必要がある | 指定しない | 指定しない |
|(page)| ページを変える際のイベント | 指定する | 指定しない | 指定する |
|(scroll)| スクロールした際のイベント | 指定しない | 指定する | 指定しない |

# サンプル解説
## Client-side
コード：https://github.com/swimlane/ngx-datatable/blob/master/src/app/paging/paging-client.component.ts

`[rows]`に全データの配列、`[limit]`に1ページあたりの件数を入れるだけです。


## Server-side
最も単純なサーバサイドページングの実装です。


コード：https://github.com/swimlane/ngx-datatable/blob/master/src/app/paging/paging-server.component.ts

`[rows]`は**そのページに属するデータのみの配列**になっています。
`[externalPaging]`は、サーバサイドでのページングを行う際にtrueにするもので、同時に以下のページングに関連するデータも指定します。

- `[count]`は全データの件数（初期表示時にサーバから取得する必要あり）
- `[offset]`はページ番号（**※0オリジンです！1ページ目は0**）
- `[limit]`は1ページあたりの件数


また、もう1つ重要なものとして`(page)`があります。これは、ページが変わったときに発火されるイベントで、ページ情報のオブジェクトが`$event`オブジェクトとして得られます。（参照：https://swimlane.gitbook.io/ngx-datatable/api/table/outputs#page　）
これをもとに、指定したページ番号のデータをサーバ側から取得→得たデータをdatatableの`[rows]`に代入、とすることでページめくりができるという仕組みです。

## Scrolling no virtual
「Server-side」で、datatableの`[scrollbarV]="true"`にしたいけど、無限スクロールページングをしたいわけじゃないんだよな・・・という場合のパターンです。

コード：https://github.com/swimlane/ngx-datatable/blob/master/src/app/paging/paging-scrolling-novirtualization.component.ts

他の「Server-side」との差は、`[virtualization]="false"`が指定されていることです。`[virtualization]`はデフォルトがtrueなので、明示的に無限スクロールじゃないと指定する必要があるためかと考えられます。

## Scrolling server-side
無限スクロールだってできます。

コード：https://github.com/swimlane/ngx-datatable/blob/master/src/app/paging/scrolling-server.component.ts

スクロールした際に発火するのが、`(scroll)`イベントです。ソースコードは長いですが、スクロールの縦方向の差分を見て次のデータを取る必要がある部分に差し掛かっているかをチェックし、指定された件数（`limit`）分次のデータを取得→`rows`の後ろにくっつけるということをします。

## Virtual server-side
「Scrolling server-side」では**スクロールによって次のページのデータを取ってくる、ということしかできない**のですが、「Virtual server-side」は無限スクロールかつ特定のページ番号に属するデータの取得ができるサンプルです。

コード：https://github.com/swimlane/ngx-datatable/blob/master/src/app/paging/paging-virtual.component.ts

「Server-side」とほとんど同じにも見えますが、違うポイントとしては「limit」の指定がないことです。
`(page)`の処理を見てみます。

ページ番号（page.pageNumber）と1ページあたりの件数（page.pageSize）を指定してサーバサイドからデータを取得→rowsのページ番号に合った位置にデータを挿入　という流れです。
この処理で、重複したデータが２度入ることがないよう、`cache`で「○○ページのデータを取得済みか？」管理しています。