【tablesorter】簡単に後付けでテーブルにソート機能を実装する【jQuery】

tablesorterというjQueryのプラグインがとても便利でした。
基本的な実装方法とソートアイコンのカスタマイズ、ソート対象項目を任意にする方法を紹介します。

[<b>tablesorter</b>](https://mottie.github.io/tablesorter/docs/index.html)


この何の変哲も無いテーブルにソート機能を実装してみます。
見た目を整えるためにbootstrapを使用してます。
また、`fav-table`というidを与えてセレクタに備えます。
<img width="1130" alt="スクリーンショット 2019-04-10 16.21.22.png" src="https://qiita-image-store.s3.amazonaws.com/0/151314/45f43c40-701e-3b19-d77e-1621c02d9c07.png">
ソース

```html

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Tablesorter Demo</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<style>
#fav-table th {
    background-color:pink;
}
</style>
</head>
<body>
<div class="card-body">
    <caption>My Favorite Album</caption>
    <table id="fav-table" class="table table-bordered">
        <thead><tr><th>Album</th><th>Artist</th><th>Country</th><th>Label</th><th>Release</th><th>Recommend</th></tr></thead>
        <tr><td>Demi Masa</td><td>simakDialog</td><td>Indonesia</td><td>Moonjune Records</td><td>2009/06</td><td>★★★★★★★★</td></tr>
        <tr><td>Postaeolian Train Robbery</td><td>CoS</td><td>Belgium</td><td>Plus Records</td><td>1974/08</td><td>★★★★</td></tr>
        <tr><td>organizer</td><td>KIYO＊SEN</td><td>Japan</td><td>ELEC RECORDS</td><td>2018/07</td><td>★★★</td></tr>
        <tr><td>Explorations</td><td>Bill Evans</td><td>America</td><td>Riverside Records</td><td>1961/03</td><td>★★★★★★</td></tr>
        <tr><td>わたしの毎日</td><td>石川ひとみ</td><td>Japan</td><td>IMPERIAL RECORDS</td><td>2018/06</td><td>★★★★★★★</td></tr>
    </table>
    </div>
</body>
</html>
```

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


<h3>tablesorterの導入</h3>

１．headにjQuery本体とtablesorterのjs、cssの読み込みを追記

```html

<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery.tablesorter/2.31.0/js/jquery.tablesorter.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jquery.tablesorter/2.31.0/css/theme.default.min.css">
```

２．ソートの実行を記述

```javascript

$(document).ready(function() {
    $('#fav-table').tablesorter();
});
```

これだけです。。。
ヘッダのカラムにソートアイコンが付いて、ヘッダをクリックするとソートが可能になりました。
<img width="1129" alt="スクリーンショット 2019-04-10 16.28.44.png" src="https://qiita-image-store.s3.amazonaws.com/0/151314/ab79201a-93f1-d76e-e0e7-cf77e5e33fa0.png">
ソース全体

```html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Tablesorter Demo</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery.tablesorter/2.31.0/js/jquery.tablesorter.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jquery.tablesorter/2.31.0/css/theme.default.min.css">
<style>
#fav-table th {
    background-color:pink;
}
</style>
<script>
$(document).ready(function() {
    $('#fav-table').tablesorter();
});
</script>
</head>
<body>
<div class="card-body">
    <caption>My Favorite Album</caption>
    <table id="fav-table" class="table table-bordered">
        <thead><tr><th>Album</th><th>Artist</th><th>Country</th><th>Label</th><th>Release</th><th>Recommend</th></tr></thead>
        <tr><td>Demi Masa</td><td>simakDialog</td><td>Indonesia</td><td>Moonjune Records</td><td>2009.06</td><td>★★★★★★★★</td></tr>
        <tr><td>Postaeolian Train Robbery</td><td>CoS</td><td>Belgium</td><td>Plus Records</td><td>1974.08</td><td>★★★★</td></tr>
        <tr><td>organizer</td><td>KIYO＊SEN</td><td>Japan</td><td>ELEC RECORDS</td><td>2018.07</td><td>★★★</td></tr>
        <tr><td>Explorations</td><td>Bill Evans</td><td>America</td><td>Riverside Records</td><td>1961.03</td><td>★★★★★★</td></tr>
        <tr><td>わたしの毎日</td><td>石川ひとみ</td><td>Japan</td><td>IMPERIAL RECORDS</td><td>2018.06</td><td>★★★★★★★</td></tr>
    </table>
    </div>
</body>
</html>
```

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


しかしいい感じだったbootstrapのスタイルが飛んでしまいました…
というわけで、ヘッダのソートアイコンのみ表示して、ほかの見た目はなにもしないで欲しい場合の対処法を紹介します。
ついでにソートアイコンを好きなものにしてみます。

<h3>ソートアイコンのカスタマイズ</h3>

１．tablesorterのスタイル読み込みを削除

```
削除する↓
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jquery.tablesorter/2.31.0/css/theme.default.min.css">
```

２．sort.png(デフォルト)、sort_a.png(昇順時)、sort_d.png(降順時)の画像を用意して以下のスタイルを追記
ちなみにアイコンはここからダウンロードしました -> https://icons8.jp/icons/

```css

.tablesorter-headerUnSorted {
    background-image: url('img/sort.png');
    background-repeat: no-repeat;
    background-position: center right;
}
.tablesorter-headerAsc {
    background-image: url('img/sort_a.png');
    background-repeat: no-repeat;
    background-position: center right;
    border-bottom: #000 2px solid;
}
.tablesorter-headerDesc {
    background-image: url('img/sort_d.png');
    background-repeat: no-repeat;
    background-position: center right;
    border-bottom: #000 2px solid;
}

```
<img width="1127" alt="スクリーンショット 2019-04-10 16.56.28.png" src="https://qiita-image-store.s3.amazonaws.com/0/151314/b0145929-38c7-6157-31be-1d9b02ff8870.png">
ソース全体

```html

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Tablesorter Demo</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery.tablesorter/2.31.0/js/jquery.tablesorter.min.js"></script>
<style>
#fav-table th {
    background-color:pink;
}
.tablesorter-headerUnSorted {
    background-image: url('img/sort.png');
    background-repeat: no-repeat;
    background-position: center right;
}
.tablesorter-headerAsc {
    background-image: url('img/sort_a.png');
    background-repeat: no-repeat;
    background-position: center right;
    border-bottom: #000 2px solid;
}
.tablesorter-headerDesc {
    background-image: url('img/sort_d.png');
    background-repeat: no-repeat;
    background-position: center right;
    border-bottom: #000 2px solid;
}
</style>
<script>
$(document).ready(function() {
    $('#fav-table').tablesorter();
});
</script>
</head>
<body>
<div class="card-body">
    <caption>My Favorite Album</caption>
    <table id="fav-table" class="table table-bordered">
        <thead><tr><th>Album</th><th>Artist</th><th>Country</th><th>Label</th><th>Release</th><th>Recommend</th></tr></thead>
        <tr><td>Demi Masa</td><td>simakDialog</td><td>Indonesia</td><td>Moonjune Records</td><td>2009.06</td><td>★★★★★★★★</td></tr>
        <tr><td>Postaeolian Train Robbery</td><td>CoS</td><td>Belgium</td><td>Plus Records</td><td>1974.08</td><td>★★★★</td></tr>
        <tr><td>organizer</td><td>KIYO＊SEN</td><td>Japan</td><td>ELEC RECORDS</td><td>2018.07</td><td>★★★</td></tr>
        <tr><td>Explorations</td><td>Bill Evans</td><td>America</td><td>Riverside Records</td><td>1961.03</td><td>★★★★★★</td></tr>
        <tr><td>わたしの毎日</td><td>石川ひとみ</td><td>Japan</td><td>IMPERIAL RECORDS</td><td>2018.06</td><td>★★★★★★★</td></tr>
    </table>
    </div>
</body>
</html>
```

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

<h4>ソート対象の項目を特定したい場合</h4>

１． ソート対象外のヘッダにアイコンが表示されないようにするスタイルを追記

```css
.sorter-false {
    background-image: none;
}
```

２． ソート実行の記述を変更（この例ではReleaseとRecommend以外をソート対象としている）

```javascript

$(document).ready(function() {
    $('#fav-table').tablesorter({
            headers: {
               0: { sorter: false },
               1: { sorter: false },
               2: { sorter: false },
               3: { sorter: false }
            }
    });
});
```
<img width="1309" alt="スクリーンショット 2019-04-10 17.33.39.png" src="https://qiita-image-store.s3.amazonaws.com/0/151314/13773133-358a-de32-daac-cd9180c25c48.png">

ソース全体

```html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Tablesorter Demo</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery.tablesorter/2.31.0/js/jquery.tablesorter.min.js"></script>
<style>
#fav-table th {
    background-color:pink;
}
.tablesorter-headerUnSorted {
    background-image: url('img/sort.png');
    background-repeat: no-repeat;
    background-position: center right;
}
.tablesorter-headerAsc {
    background-image: url('img/sort_a.png');
    background-repeat: no-repeat;
    background-position: center right;
    border-bottom: #000 2px solid;
}
.tablesorter-headerDesc {
    background-image: url('img/sort_d.png');
    background-repeat: no-repeat;
    background-position: center right;
    border-bottom: #000 2px solid;
}
.sorter-false {
    background-image: none;
}
</style>
<script>
$(document).ready(function() {
    $('#fav-table').tablesorter({
            headers: {
               0: { sorter: false },
               1: { sorter: false },
               2: { sorter: false },
               3: { sorter: false }
            }
    });
});
</script>
</head>
<body>
<div class="card-body">
    <caption>My Favorite Album</caption>
    <table id="fav-table" class="table table-bordered">
        <thead><tr><th>Album</th><th>Artist</th><th>Country</th><th>Label</th><th>Release</th><th>Recommend</th></tr></thead>
        <tr><td>Demi Masa</td><td>simakDialog</td><td>Indonesia</td><td>Moonjune Records</td><td>2009.06</td><td>★★★★★★★★</td></tr>
        <tr><td>Postaeolian Train Robbery</td><td>CoS</td><td>Belgium</td><td>Plus Records</td><td>1974.08</td><td>★★★★</td></tr>
        <tr><td>organizer</td><td>KIYO＊SEN</td><td>Japan</td><td>ELEC RECORDS</td><td>2018.07</td><td>★★★</td></tr>
        <tr><td>Explorations</td><td>Bill Evans</td><td>America</td><td>Riverside Records</td><td>1961.03</td><td>★★★★★★</td></tr>
        <tr><td>わたしの毎日</td><td>石川ひとみ</td><td>Japan</td><td>IMPERIAL RECORDS</td><td>2018.06</td><td>★★★★★★★</td></tr>
    </table>
    </div>
</body>
</html>
```

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


<h4>補足</h4>

`2019-04-02T20:18:24`のような文字混じりなフォーマットの場合、意図した動作をしないことがあります。
そんなときはaddParserメソッドを使用して独自のフォーマットを定義します。
以下はreleaseを数字のみに変換し、タイプを文字列型に指定しています。

```javascript
    //releaseのフォーマットを定義
    $.tablesorter.addParser({
        id: 'release', 
        is: function(s) { 
            return false;
        },
        format: function(s) {
                return s.toLowerCase().replace(/[^0-9]/g,'');
            },
        type: 'string'
    });

    $('#fav-table').tablesorter({
            headers: {
               0: { sorter: false },
               1: { sorter: false },
               2: { sorter: false },
               3: { sorter: false }
            }
    });
```