List.jsでHTMLのテーブルをページ分割してソートする

list.jsを使って難しいことを簡単に。

#はじめに
前に作ったソートのサンプルにページ分割の仕組みを入れます。HTML描画時に全データがTableとして出力されているものを対象とします。ページを動きながらデータを取りに行くようなものではありません。画面内でゴリゴリとやるのでパフォーマンスに難が出るかもしれません。

#やること
普通のHTMLテーブルをlist.jsを使って、ソートしつつページ分割します。

#使ったもの
[list.js (version 1.5)](http://listjs.com)

#やってみよう
## 1.HTMLのテーブルを用意する
前回のサンプルの再掲です。
- ヘッダーのカラムをクリックするとasc/descの切り替えができる
- 切り替えたあとに▲/▼の表示が付く
- HTMLテーブルの内容によらず、初期表示は名前の昇順　~~生まれ年の逆順~~

```html:zenkai.html
<div id="users">
  <table>
    <thead>
      <tr>
        <th class="sort" data-sort="name">Name</th>
        <th class="sort" data-sort="born">Born</th>
      </tr>
    </thead>
    <!-- IMPORTANT, class="list" have to be at tbody -->
    <tbody class="list">
      <tr>
        <td class="name">Jonny Stromberg</td>
        <td class="born">1986</td>
      </tr>
      <tr>
        <td class="name">Jonas Arnklint</td>
        <td class="born">1985</td>
      </tr>
      <tr>
        <td class="name">Martina Elm</td>
        <td class="born">1986</td>
      </tr>
      <tr>
        <td class="name">Gustaf Lindqvist</td>
        <td class="born">1983</td>
      </tr>
    </tbody>
  </table>
</div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/list.js/1.5.0/list.min.js"></script>
<script>
var options = {
  valueNames: [ 'name', 'born' ]
};
var userList = new List('users', options);
userList.sort( 'name', {order : 'asc' });
</script>

<style>
.sort.desc:after {
  content:"▼";
}
.sort.asc:after {
  content:"▲";
}
</style>
```

このままだとテーブルのデータが少なくページ移動する実感がなくなるので、いい感じで増やしてください。以降のサンプルは30個に増やしたときの例です。

##2. page分割(paginate)の設定する
list.jsの初期化の部分を修正します。

```javascript
  var options = {
    valueNames: [ 'name', 'born' ],
    page: 2,
    pagination: {
        paginationClass:'pagination',
        innerWindow:1,
        outerWindow:1,
    }
  };
  var userList = new List('users', options);

```

###page
1ページあたりの行数を指定できます。指定しない場合は200になるそうです。

###pagination
ページャーのパーツの動きを設定します。マニュアルを見ると以下のプロパティが指定できます（一部意訳）
**paginationClass**
ページを動かすためのHTMLのパーツの埋め込むためのclass名を指定する。何も指定しないときは、"pagination"

**innerWindow**
今のページの前後に何ページ移動可能にするかを数値で指定する。何も指定しないときは "2"。5ページ目にいるときは、前向きに3,4 後ろ向きに6,7が移動できるようになる。

**outerWindow**
今いるところとは関係なしに両端を何ページ出すかを指定する。何も指定しないときは "0"の扱い。全部で何ページあるかを表現できるので1は指定しておきたいところ。

**left**
outerWindowと同じだが、左端（1ページ目）から何個ジャンプできるようにするかを指定する。

**right**
leftと同じ。右端（最終ページ）から何ページを直接移動できるようにするか指定できる。

今回の設定だと、1ページ2行表示、隣のページには1ページまで移動できる、両端のページも1ページ移動でいる状態となります。leftとrightは使っていませんが、左右非対称にしたいときは使ってみてください。outerWindowで足りそうですけど。

##3.ページャーを埋め込む
このままだとページ移動のパーツは表示されません。list.jsにはページ移動のパーツを埋め込む仕組みがあるので活用します。といっても、以下のHTMLを入れるだけです。

```html
<ul class="pagination"></ul>
```

ブラウザで再読み込みすると、こんな感じのパーツが出てきます。4ページ目まで移動したところです。前後に1ページ分のリンク、今いる場所に関係なく、1ページ目と15ページ目へのダイレクトリンクがあります。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/168315/9b2f91f2-82e7-34e1-10ad-d9e028e7f327.png)


``<ul>``タグ、``<li>``タグでpaginateのパーツが描画されます。自動で出力されるページャーは簡単なHTMLの構造なのでCSSで味付けしときます。CSSは[こちらのページ](http://wwx.jp/css-pagination)を参考にさせていただきました。こちらのCSSを丸っと使うために、```<div class="pager">```で囲いました。

```html
    <div class="pager">
        <ul class="pagination"></ul>
    </div>
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/168315/83c280a0-ee62-1356-ac6d-749a1875ca23.png)

##4.ソートした時の挙動を変える
この状態でほぼ完成かと思ったのですが、ページ移動後にカラムヘッダーを使ってソートすると、データの並び替えは行われますがページ番号がそのまま（サンプルだと4のまま）なので、不思議な挙動をします。ソートしたときはページ番号が1にリセットされるのが期待する動きかなと思うので、その部分を追加しておきます。不要であれば撤去してください。

```javascript
  userList.on('sortStart', function(list){
      console.log(list.i);
      list.i=1;
    }
  );
```
userListオブジェクトにイベント発生時のコールバックを仕込みました。ソートが始まるときに呼ばれる関数内でlistの番号を1にします。list.jsのイベントは[こちらのページ](https://qiita.com/kanaxx/items/4b16f5a884d1b0f4abaf)で解説してあります。



#完成品です

```html
<div id="users">
    <table>
      <thead>
        <tr>
          <th class="sort" data-sort="name">Name</th>
          <th class="sort" data-sort="born">Born</th>
        </tr>
      </thead>
      <!-- IMPORTANT, class="list" have to be at tbody -->
      <tbody class="list">
        <tr>
          <td class="name">1.Jonny Stromberg</td>
          <td class="born">1986</td>
        </tr>
        <tr>
          <td class="name">2.Jonas Arnklint</td>
          <td class="born">1985</td>
        </tr>
        <tr>
          <td class="name">3.Martina Elm</td>
          <td class="born">1986</td>
        </tr>
        <tr>
          <td class="name">4.Gustaf Lindqvist</td>
          <td class="born">1983</td>
        </tr>

<!--省略-->

          <tr>
            <td class="name">29.Martina Elm</td>
            <td class="born">1986</td>
          </tr>
          <tr>
            <td class="name">30.Gustaf Lindqvist</td>
            <td class="born">1983</td>
          </tr>
    
    </tbody>
    </table>

    <!-- wrap list.js pagination by div.pager for using pager sample css -->
    <div class="pager">
        <ul class="pagination"></ul>
    </div>

  </div>
  
  <script src="https://cdnjs.cloudflare.com/ajax/libs/list.js/1.5.0/list.min.js"></script>
  <script>
  var options = {
    valueNames: [ 'name', 'born' ],
    page: 2,
    pagination: {
        paginationClass:'pagination',
        innerWindow:1,
        outerWindow:1,
    }
  };
  var userList = new List('users', options);

  userList.on('sortStart', function(a){
      console.log(a.i);
      a.i=1;
    }
  );

  //for initial sort
  userList.sort( 'name', {order : 'asc' });
  </script>
  
<style>
/* style for sort */
  .sort.desc:after {
    content:"▼";
  }
  .sort.asc:after {
    content:"▲";
  }
</style>

<style>
/* style for pager and pagination from http://wwx.jp/css-pagination*/

.pager {
    overflow: hidden;
}
 
.pager ul {
    list-style: none;
    position: relative;
    left: 50%;
    float: left;
}
 
.pager ul li {
    margin: 0 1px;
    position: relative;
    left: -50%;
    float: left;
}
 
.pager ul li span,
.pager ul li a {
    display: block;
    font-size: 16px;
    padding: 0.6em 1em;
    border-radius: 3px;
}
 
.pager ul li a {
    background: #EEE;
    color: #000;
    text-decoration: none;
}
 
.pager ul li a:hover {
    background: #333;
    color: #FFF;
}

/* added by myself */
.pager ul li.active{
    font-weight: bold;
}
</style>
```

コードをそのままHTMLファイルとして保存すれば動きます。

#まとめ
今回のpaginationはCSSを直接書きましたが、bootstarpのpaginationと仕組みは同じような感じなので、そのまま使えるのではないかと思います。ページャー、ページネイト、ニホンゴムズカシイネ

#参考にしたページ
http://listjs.com/docs/pagination/
http://wwx.jp/css-pagination