HTMLのtableをソートする方法

# 概要
- Tableをソートするライブラリを書きました
  - 外部ライブラリなどは不要
  - シンプルなので素のHTMLやBootstrapなど特にフレームワーク縛りなく使える
  - **ソートのみ**が欲しかったので容量小さめ

- ソースコードはこちらで公開しています
   - https://github.com/riversun/sortable-table
- NPMパッケージ化したものはこちら
   - https://www.npmjs.com/package/@riversun/sortable-table

# デモ

<p class="codepen" data-height="445" data-theme-id="light" data-default-tab="html,result" data-user="riversun" data-slug-hash="OJVEVpa" style="height: 445px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="sortable-table (with Bootstrap4)">
  <span>See the Pen <a href="https://codepen.io/riversun/pen/OJVEVpa">
  sortable-table (with Bootstrap4)</a> by Tom Misawa (<a href="https://codepen.io/riversun">@riversun</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

# 使い方

## TableのHTML

- **sortable-table**クラスをもった要素以下に**table thead**を置く
- th要素に**data-id**属性でデータとひもづけるidを指定する
- ソートしたい列には**sortable**属性をつける

以下のようになる。

```html:ソートできるテーブルのHTML
<div class="sortable-table">
    <table id="my-table1">
        <thead>
        <tr>
            <th data-id="id" data-header>
                <div>#</div>
            </th>
            <th data-id="name" sortable>
                name
            </th>
            <th data-id="price" sortable>
                price($)
            </th>
            <th data-id="weight" sortable>
                weight(carat)
            </th>
        </tr>
        </thead>
    </table>
</div>
```

## テーブルにデータを入れる

- 以下のようにテーブルに表示させたいデータを行ごとに配列で指定する
- 要素名とさきほどHTMLで定義した**data-id**属性が紐付く

```javascript
 const data = [
    {
      id: 0,
      name: 'Diamond',
      weight: 1.0,
      price: 9000,
    },
    {
      id: 1,
      name: 'Amethyst',
      weight: 3.0,
      price: 200,
    },
    {
      id: 2,
      name: 'Emerald',
      weight: 2.5,
      price: 2500,
    },
    {
      id: 3,
      name: 'Ruby',
      weight: 2.0,
      price: 2000,
    },
  ];

  const sortableTable = new SortableTable();
  // table要素を指定する
  sortableTable.setTable(document.querySelector('#my-table1'));
  // テーブルに表示したいデータを指定する
  sortableTable.setData(data);
```

- **setTable**でソートできるようにしたいtable要素を指定する
- **setData**でテーブルに表示したいデータを指定する


<p class="codepen" data-height="265" data-theme-id="light" data-default-tab="js,result" data-user="riversun" data-slug-hash="vYOrEbJ" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="sortable-table (with plain HTML)">
  <span>See the Pen <a href="https://codepen.io/riversun/pen/vYOrEbJ">
  sortable-table (with plain HTML)</a> by Tom Misawa (<a href="https://codepen.io/riversun">@riversun</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

## ソートした結果を受け取り処理する

ソート結果は**getData**で取得できる。
**setData**で元のデータを指定するが、ソートしても<font color=red>元のデータは変更しない</font>ようにしているので、ソート済のデータを取得したい場合は**getData**か後述のイベントコールバックから取得する。


```javascript
const sortedData=sortableTable.getData();
```


## ソートイベントを受け取る

テーブルのヘッダ部分がクリックされ、ソートが実行されるとソートイベントが発火する
以下のようにイベントリスナーを登録するとソートされたときイベントがコールバックされる。

```javascript
  sortableTable.events()
    .on('sort', (event) => {
      console.log(`[SortableTable#onSort]
      event.colId=${event.colId}
      event.sortDir=${event.sortDir}
      event.data=\n${JSON.stringify(event.data)}`);
    });
```

- **event.colId**には列のid(=**data-id**)が格納される
- **event.sortDir**にはソート方向(=**asc** or **desc**)
- **event.data**にはソート済のデータが格納される

## ソートをコードから実行する

ユーザーのクリックではなく、コードからソートを（強制的に）実行する方法は以下の通り

```javascript:ソートをコードから実行する
sortableTable.sort('price', 'asc');
```

**sortableTable.sort([id], [sortDir]);**のように指定する。

**sortDir**にソート方向を指定する
- **asc**・・・昇順ソート。昇順とは 1,2,3,4 のようになる
- **desc**・・・降順ソート。降順とは4,3,2,1　のようになる
- **toggle**・・・現在のソート方向を反転する。

## ソートを初期状態に戻す

最初にデータを指定したときの状態に戻すときは**resetData**

```javascript:初期状態に戻す
sortableTable.resetData();
```

### ソートをコードから実行するデモ
https://riversun.github.io/sortable-table/index_with_bootstrap.html


## セルの中身を装飾する

セルに値を表示するだけでなく、HTML要素やCSSなどで装飾したい場合は、`setCellRenderer`メソッドを使う
セルのスタイルをデータのカラムのid(`col.id`)ごとにだし分けることができる。

以下の例では`col.id`が`"url"`の場合`a`タグでかこってリンクにしている。

```js

 // set callback function for table cell custom rendering
  sortableTable.setCellRenderer((col, row) => {
    const colValue = row[col.id];
    // cell-is-a-header
    if (col.isHeader) {
      if (typeof colValue !== 'undefined') {
        return `<th>${colValue}</th>`;
      }
      return '<th></th>';
    }
    // cell-is-not-a-header
    if (typeof colValue !== 'undefined') {
      if (col.id === 'url') {
        return `<td><a href="${colValue}" target="_blank">${colValue}</a></td>`;
      }
      return `<td>${colValue}</td>`;
    }
    return '<td></td>';
  });
```

デモ

<p class="codepen" data-height="265" data-theme-id="light" data-default-tab="js,result" data-user="riversun" data-slug-hash="mdPZemb" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="sortable-table custom rendering">
  <span>See the Pen <a href="https://codepen.io/riversun/pen/mdPZemb">
  sortable-table custom rendering</a> by Tom Misawa (<a href="https://codepen.io/riversun">@riversun</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>


# まとめ
- 拙作のソートライブラリについてお読みいただきありがとうございました
- 何かのお役にたてますと幸いです

## ソースコードについて
- Githubで公開しています
   - https://github.com/riversun/sortable-table

- npm/yarnから利用可能です

```
npm install @riversun/sortable-table
```

- CDNからも利用可能です

```
<script src="https://cdn.jsdelivr.net/npm/@riversun/sortable-table/lib/sortable-table.js"></script>
```