Angular : Firestoreのデータをページネーションしたい② ～ Material2のPaginatorを使う

#Angular : Firestoreのデータをページネーションしたい② ～ Material2のPaginatorを使う

前回：[Angular : Firestoreのデータをページネーションしたい① ～ 超簡単なやり方](https://qiita.com/atomyah/items/c38960712c33acac9865)

せっかくカッコいいMaterial2のPaginatorという部品があるので使ってみたい。正式マニュアルはこちら。[Paginator](https://material.angular.io/components/paginator/overview)

###環境

```
Angular CLI: 7.1.4
Node: 10.15.3
OS: win32 x64
Angular: 7.1.4

"@angular/material": "^7.3.4"
```
###app.module.ts
Material2を使用中ならいつもの通り。app.module.tsにMatPaginatorModuleを追記。
<strong>app.module.ts

```typescript
import {MatPaginatorModule} from '@angular/material/paginator';

@NgModule({
   //モジュール
  imports: [
    MatPaginatorModule,
   ]
```

###Paginatorを張り付ける
まずはUIにMaterial2のPaginatorを張り付ける。上記環境にあるようにMaterial2は導入済みとする。HTMLは以下の通り。

```html
<mat-paginator [length]="length"
              [pageSize]="perPage"
              [pageSizeOptions]="[10, 50, 100]"
              (page)="getPaginatorData($event)" 
>
</mat-paginator>
```

これでこのようなUIになる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307441/103c3671-6ca9-d720-5b5d-8256a5372e59.png)

- [length]="length"：全データ件数(上図ではデフォルトの100)
- [pageSize]="perPage"：1ページあたりに表示する件数初期値(上図では10)
- [pageSizeOptions]="[10, 50, 100]"：perPage数を選ぶセレクトボックス
- (page)="getPaginatorData($event)" ：イベント発生時に発火させる関数


これでPaginator UIができた。したらそれぞれの変数をFirestoreからとってきたデータに紐づける。

###Firestoreデータへの紐づけ
コントローラーに、①[前回](https://qiita.com/atomyah/items/c38960712c33acac9865)説明したsliceに使う各変数を設定して②MatPaginatorをオブジェクト化して③関数getPaginatorData($event)を書く。

```typescript
import {MatPaginator} from '@angular/material';

　// 各変数の宣言と初期値設定
  length: number; //ページネーションで使う全書き込み件数
  pageIndex: number = 0; //ページネーションで使うページインデックス
  perPage: number = 50; //ページネーションで使うページ当たりのデータ数
  lowValue: number = 0; //ページネーションのsliceで使うbegin値
  highValue: number = 50;　//ページネーションのsliceで使うbegin+perPage値

  // MatPaginatorイベントをオブジェクト化
    pageEvent: MatPaginator;

  // イベント発火関数
    public getPaginatorData(event) {
      this.lowValue = event.pageIndex * event.pageSize;
      this.highValue = this.lowValue + event.pageSize;
      return event;
    }
```

簡単な関数やのう。Thankyou [avokado](https://stackoverflow.com/users/11768869/avokado)!!!!

いろいろググると、MatTableDataSourceをインポートして、dataSourceを作って… とあるけれど。
こんなように:point_down_tone2:
`dataSource : MatTableDataSource<Post>;`
`this.dataSource = new MatTableDataSource<Post>(response['results']);`
これ要らないね。そういうやり方もあるということかな。

###length（全データ件数）は？
最後にlength（全データ件数）をFirestoreから取ってきてlengthに格納するやり方。

```typescript
  // の全データ件数を獲得しlengthに保存
  getDataSize() {
    this.db.collection('commentsfaqs').valueChanges().subscribe( values => {
      console.log('■データ数は、' + values.length);
      this.length = values.length
    })
  }
```

これはローカルにロードしてカウントするやり方なので数百件程度の量なら有効とのこと。数千以上になるとFirebase Funcionを使うやり方のほうがいいらしい。getDataSize()はngOnInit(){...}に突っ込んで最初に実行させておく。

<br>
コンポーネントの全文は以下の通り（ページネーションに関係ないコードは割愛してる。うまく読み取っておくれ）

```typescript
import {MatPaginator} from '@angular/material';

/* ページネーションに使用する変数と関数 */
  length: number; //ページネーションで使う全書き込み件数
  pageIndex: number = 0; //ページネーションで使うページインデックス初期値
  perPage: number = 50; //ページネーションで使うページ当たりのデータ数初期値
  lowValue: number = 0; //ページネーションのsliceで使うbegin値初期値
  highValue: number = 50;　//ページネーションのsliceで使うbegin+perPage値初期値

  ngOnInit() {
    this.getDataSize();
  }

  // MatPaginatorイベントをオブジェクト化
    pageEvent: MatPaginator;

  // の全データ件数を獲得しlengthに保存
  getDataSize() {
    this.db.collection('comments').valueChanges().subscribe( values => {
      console.log('■データ数は、' + values.length);
      this.length = values.length
    })
  }

  // Paginatorからのイベント発火関数
    public getPaginatorData(event) {
      this.lowValue = event.pageIndex * event.pageSize;
      this.highValue = this.lowValue + event.pageSize;
      return event;
    }
/* ページネーションに使用する変数と関数 ~ここまで */
```
HTMLのほう

```html
<div style="display:inline-block; width: 100%" *ngFor="let post of posts | async | slice: lowValue : highValue">
        <p>名前：{{ post.userName }}</p>
        <p>メッセージ：{{ post.userName }}</p>
        <p>投稿日時：{{ post.created }}</p>
</div>
```

<br>

###（補足）日本語化
AngularやMaterial2のバージョンが違うが、[AngularMaterialのPaginatorを日本語化する](https://qiita.com/drafts/c38960712c33acac9865/edit) のとおりのやり方でうまくいった。

こんな感じです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307441/88d86e88-3b31-14f4-577e-8a658024eb33.png)

###（補足）showFirstLastButtons
HTMLに以下のパラメータをつけると最初と最後のページに移動する矢印が追加できる。
`[showFirstLastButtons]="true"`

```html
<mat-paginator [length]="length"
              [pageSize]="perPage"
              [pageSizeOptions]="[10, 50, 100]"
              (page)="getPaginatorData($event)" 
              [showFirstLastButtons]="true"
>
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307441/4193a7e3-e6ea-da54-ba1d-b649c0bf4f58.png)

<br>
参照：[How to use paginator from material angular?](https://stackoverflow.com/questions/45318164/how-to-use-paginator-from-material-angular)
<br>