jQueryのTablesorterを複数行のヘッダに対応させる方法

JavaScriptライブラリのjQueryには、テーブルをソートするためのTablesorterというプラグインがあります(デモ)。これを複数行にまたがるヘッダに対応させる方法を紹介します。

複数行のヘッダというのは、2つ以上のtr要素やrowspan/colspan属性付きのth要素を含むthead要素のことです。Tablesorterの紹介にはSupport for ROWSPAN and COLSPAN on TH elementsとありますが、自動的に対応してくれるわけではないようです(あるいは、将来的にサポート予定なのか)。

解決の糸口となったのはjQueryグループの「jquery tablesorter 2.0.1 with tr in thead」というスレッドです。他にも似た質問がいくつか見つかったので、同じようなことで躓いている人は多いようです。

tablesorterオブジェクトにはheaderListというそれっぽいプロパティがあるのですが、上手くいかなかったので今回の方法を採用しました。

前提となるXHTML

ここでは、次のような複数行(colspan, rowspan属性付き)のth要素を含むテーブルを例にします。

製品価格一覧
製品名 価格
新規 アップグレード
製品A 49800 26000
製品B 39690 12390
index.html(抜粋)
<table>
  <caption>製品価格一覧</caption>
  <thead>
    <tr>
      <th scope="col" rowspan="2">製品名</th>
      <th scope="col" colspan="2">価格</th>
    </tr>
    <tr>
      <th scope="col">新規</th>
      <th scope="col">アップグレード</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th scope="row">製品A</th>
      <td>49800</td>
      <td>26000</td>
    </tr>
    <tr>
      <th scope="row">製品B</th>
      <td>39690</td>
      <td>12390</td>
    </tr>
  </tbody>
</table>

単純にTablesorterを呼び出すだけでは、このようなテーブルは正しくソートできません。「製品名」・「新規」・「アップグレード」の各th要素をソートのトリガーにしようというのが今回の目的です。

必要なもの

この方法でTablesorterを複数行のヘッダに対応させるには、次のものが必要になります。

jQuery本体とTablesorterプラグインはもちろん必要です。Metadataプラグインは、属性値に埋め込んだメタデータ(JavaScriptのオブジェクトリテラルと同じ書式)をオブジェクトに変換してくれるプラグインです。ソートのトリガーとなるth要素を手動で指定するために使います。

Tablesorterプラグインの修正

まず、jquery.tablesorter.js内のbuildHeaders()メソッドを次のコードに入れ替えます。

jquery.tablesorter.js buildHeaders()メソッド
function buildHeaders(table) {
    if (table.config.debug) { var time = new Date(); }

    var meta = ($.metadata) ? true : false, tableHeadersRows = [];

    for (var i = 0; i < table.tHead.rows.length; i++) { tableHeadersRows[i]=0; };

    $tableHeaders = $("thead th",table);

    $tableHeaders.each(function(index) {
        var sortIndex;

        if ($.metadata && $(this).metadata().sortIndex) {
            sortIndex = $(this).metadata().sortIndex;
        } else {
            sortIndex = index;
        }

        this.count = 0;
        this.column = sortIndex;
        this.order = formatSortingOrder(table.config.sortInitialOrder);

        if (checkHeaderMetadata(this) || checkHeaderOptions(table,sortIndex)) this.sortDisabled = true;

        if (!this.sortDisabled) {
            $(this).addClass(table.config.cssHeader);
        }

        // add cell to headerList
        table.config.headerList[sortIndex] = this;
    });

    if (table.config.debug) { benchmark("Built headers:", time); log($tableHeaders); }

    return $tableHeaders;
};

これは、Metadataプラグインを使ったソートインデックスの指定に対応させるものです。

ソートインデックスの指定

Tablesorterを呼び出すためのJavaScriptファイルを作成します(ここではわかりやすいようにベタ書きにします)。

次に、各th要素に手動でソートインデックスを割り振ります。ソートインデックスは、ソートのトリガーとして使うth要素を指定するためのものです。XHTMLの任意の属性値に{ sortindex: 数字 }という書式で埋め込みます。

今回は、ソートインデックスをclass属性として埋め込むことにします。また、直に埋め込むのはよくないので、jQueryを使って動的に埋め込むことにします。

sortindexにはth要素に対応するテーブルの列を指定します。例えば、XHTML上で3番目に出現するth要素をテーブルの2列目に関連付けるには、3番目のth要素に{ sortindex: 1 }を指定します(インデックスは0から始まります)。ソートのトリガーとして使わないth要素には、余ったsortindexを指定しておきます。

my.js
$(document).ready(function() {
    // 1番目のth要素: 1列目をソート
    $('table.data thead th:eq(0)').addClass('{ sortIndex: 0 }');

    // 2番目のth要素: 4列目をソート
    // 使わないので余ったインデックスを割り振る
    $('table.data thead th:eq(1)').addClass('{ sortIndex: 3 }');

    // 3番目のth要素: 2列目をソート
    $('table.data thead th:eq(2)').addClass('{ sortIndex: 1 }');

    // 4番目のth要素: 3列目をソート
    $('table.data thead th:eq(3)').addClass('{ sortIndex: 2 }');
});

Tablesorterの呼び出し

続けて、Tablesorterを呼び出します。

このとき、ソートのトリガーとして使わないth要素(ソートインデックス)には、sorterプロパティにfalseをセットして無効化しておきます。

my.js
$(document).ready(function() {
    // 1番目のth要素: 1列目をソート
    $('table.data thead th:eq(0)').addClass('{ sortIndex: 0 }');

    // 2番目のth要素: 4列目をソート
    // 使わないので余ったインデックスを割り振る
    $('table.data thead th:eq(1)').addClass('{ sortIndex: 3 }');

    // 3番目のth要素: 2列目をソート
    $('table.data thead th:eq(2)').addClass('{ sortIndex: 1 }');

    // 4番目のth要素: 3列目をソート
    $('table.data thead th:eq(3)').addClass('{ sortIndex: 2 }');

    $('table.data').tablesorter({
        headers: {
            3: { sorter: false }  // 2番目のth要素: 4列目のソートを無効化
        }
    });
});

JavaScriptファイルへのリンク

後は、XHTMLのhead要素内でJavaScriptファイルを読み込ませれば完成です。

index.html(抜粋)
<script src="jquery.js" type="text/javascript"></script>
<script src="jquery.metadata.js" type="text/javascript"></script>
<script src="jquery.tablesorter.js" type="text/javascript"></script>
<script src="my.js" type="text/javascript"></script>

これで、複雑な表組みの場合にもTablesorterが使えるようになりました。便利です :D

コメント (2)

おかげさまで、ソートができるようになりました。ありがとうございます。

こちらですが、行方向に結合したテーブルだけではなく、列方向に結合したテーブルだったとしても有効でしょうか。

コメントフォーム

トラックバック (1)

[…] jQueryのTablesorterを複数行のヘッダに対応させる方法 関連記事 […]

この記事のトラックバックURI
http://dxd8.com/archives/118/trackback/
この記事のURI
http://dxd8.com/archives/118/