jQuery のプラグイン Tablesorter で日付等をきちんと解釈してソートさせる方法
自己満足なページではあるが私の一口馬主のページでトップに一口出資した競走馬のリストをテーブル形式で作成し、メニューとしているのだが、長年やっていると数も多くなってきた。こうなってくると、馬名や生年、更新日などでソートしてみたくなる。HTML の Table でソートするためにはどうすればいいんだろう?
そこで、下記のページで紹介されている、jQuery のプラグインである Tablesorter というのを利用することにした。
TablesorterでHTMLの表をソート(並び替え)可能にする [ホームページ作成] All About
使い方については上記のサイトに詳しく書いてある。jQuery とは Javascript の有名なライブラリであり、使用している人も多いと思うが、「何それ?」という人も Tablesorter のパッケージの中に同梱されているので、上記サイトを参考に使ってみよう。
そのページに書いてある通りに Tablesorter を導入したら、概ねソートできるようになったが、日付部分がうまくソートされないという問題があった。
下記の画像でテーブルの左から4つ目「更新日」でソートしたら、うまく日付順に並んでいない。
更新日は日付を YY/MM/DD 形式で書いているのだが、それがうまくソートされておらずメチャクチャになっている。一番ソートする機会が多い項目なのに何故???単純文字列でソートしても上手くいく筈なのに…。
おそらく日付は(文字列ではなく)日付として解釈されているのだが、アメリカ式の記述法(DD/MM/YY)で解釈されてるのだろう。
中途半端なことをするよりなら単純に文字として比較して欲しいのに。そのために今まで例えば16年9月3日だと"16/9/3"って書いてたものを"16/09/03"という風に1桁部分は0埋めして書き直したのに、それでもうまくいかないなんて。
そこで、いろいろ調べてみたら Tablesorter では、 Parser (つまり構文解析ツール)を javascript で定義して組み込むことができるとのことなので、それを使ってみた。
日付のソートがうまくできるように、以下のように Parser を使って、ソート方法を定義し直した。
//ソート(jQueryプラグイン tablesorter利用) //Parser を定義 $.tablesorter.addParser({ id: 'date', //ID を設定する is: function(s) { //通常は false を返す様に作るとマニュアルに書いてある return false; }, format: function(s) { //数字の部分だけ取り出す return s.toLowerCase().replace(/[^0-9]/g,''); }, //文字列として処理する type: 'string' }); //Tablesorter 本体 $("#list").tablesorter({ headers: { 3: { sorter:'date' }, //4列目に"date"という ID の Parser を使用 4: { sorter: false }, //5列目はソートしない 5: { sorter: false } //6列目もソートしない } });
ちなみに headers で指定する文字番号は 0 オリジンである。
上記の Parser を定義して、更新日でソートしてみた結果が以下の画像。
これでちゃんと「更新日」が YY/MM/DD 形式で解釈されてソートできた。
この様にソートの値の解釈の仕方を Javascript で定義できるので Tablesorter の Parser は便利である。(ってか日付は普通にデフォルトで文字として解釈しろよ。)
Parser について詳しいことはドキュメントのここ(英語)に書いてある。今度使う機会があったらいろいろと試してみよう。
2019/1/29 追記
上記の例は「日付を文字列として扱う方法」だが、読者の方より「曜日によって整列する」方法もあったほうが良いというご意見をいただいたので、曜日でソートする Parser を記述してみよう。
上記のプログラムの「//Parser を定義」の部分を以下のように書けば曜日によってソートできる。
//Parser を定義 $.tablesorter.addParser({ id: 'jpdays', //ID を設定する is: function(s) { //通常は false を返す様に作るとマニュアルに書いてある return false; }, format: function(s) { //並べたい順番に番号を付ける if(s.match("月")){ s = "1"; }else if(s.match("火")){ s = "2"; }else if(s.match("水")){ s = "3"; }else if(s.match("木")){ s = "4"; }else if(s.match("金")){ s = "5"; }else if(s.match("土")){ s = "6"; }else if(s.match("日")){ s = "7"; //週の始まりを月曜日ではなく日曜日にしたい場合はここは'0'とする }else{ s = "9"; //どれにもマッチしない時は最後に持っていく } return s; }, type: 'string' });
これで曜日でソートできます。
汎用性を考えて if-else文を多用して長ったらしく書いたが、ソート対称の列に必ず「月」とか「火」などと決まった形式(この場合曜日を一文字)で入っているのであれば、連想配列を使って javascript を書くことでもっとすっきりする筈。