サーバで実行させない!テーブルのソート

HTML table のソートをサーバーサイドで実行しないでクライアント側だけで実行しようと思いました。

コンセプトは、

・table の各セルのデータ(ソート対象の値)を JSONデータ、”列名”:値 のハッシュ、行を配列、として構成する。

・1行の trタグで囲まれたデータを1行を表すハッシュに、Object値とて保持する。
  → つまり、
{ "列1":"列1の値" , "列2":"列2の値" , 行 trタグObject }
という1行のデータの行数分の配列データ

・table から読み込んで生成しらJSON配列を JavaScript sort関数でソートする。

という考えに基づくソート結果の表示です。

実現の為にJSONデータのソート関数部分は、小粋空間 様が書いてくれた関数を使わせてもらいました。(感謝)

表を表示する table のソート関数として可能なかぎり普遍的に書いてみました。→ tablesort.js と名付けました。

/**
 * tablesort.js
 */

var data = [];
var trcount = 0;
var sorted;
var tbodyselector;
/*
 * tbody  : ソート対象が格納さらた table の tbody を指すセレクタ
 * firstSortId : 初期表示時の並び順に該当するリンク a タグの id 属性値
 * params : ソート対象データを列毎に JSON データで持つ時の JSON キーと
 *     起動時に table から読み込む時、行の列毎に実行するデータをJSONに格納で
 *     実行する関数を、格納するキー名と関数を指定する。
 *     格納するキー名は、リンククリック時のソート実行定義を行う関数 asignSort の引数になる。
 *           {  'jsonkey' : function ,  }
 */

var tableSortInit = function(tbody, firstSortId, params){
   tbodyselector = tbody;
   sorted = firstSortId;
   $(tbody).children('tr').each(function(i, tr){
      var row = {};
      for(var jkey in params){
         row[jkey] = params[jkey](tr, trcount);
      }
      row["trobj"] = $(tr);
      data[trcount] = row;
      trcount++;
   });
};
/*
 * ソート列定義
 * asclinkId  : 昇順リンクタグの id 属性値
 * downlinkId : 降順リンクタグの id 属性値
 * jsonKey    : JSONデータとしてソートデータ保持するための列に対するKey
 * callbacks  : ソート時のコールバック関数を指定する。(省力可)
 *               昇順、降順、各々のソート時のコールバック関数を指定する。
 *               "asc"=昇順、"desc"=降順  のキー名で指定する。
 *               省略した場合、数値によるソートになる。
 *             { 'asc' : function(a){ return a; },
 *               'desc': function(a){ return a; }, }
 */

var asignSort = function(asclinkId, downlinkId, jsonKey, callbacks){
   $('#' + asclinkId).click(function(){
      if (typeof(callbacks) == 'undefined'){
         data.sort(sort_by(jsonKey, false));
      }else{
         if (typeof(callbacks['asc']) == 'undefined'){
            data.sort(sort_by(jsonKey, false));
         }else{
            data.sort(sort_by(jsonKey, false, callbacks['asc']));
         }
      }
      makeTableBody();
      $("#"+sorted).removeClass("sorted");
      $("#"+sorted).addClass("sorter");
      $(this).addClass("sorted");
      sorted = $(this).attr('id');
   });
   $('#' + downlinkId).click(function(){
      if (typeof(callbacks) == 'undefined'){
         data.sort(sort_by(jsonKey, true));
      }else{
         if (typeof(callbacks['desc']) == 'undefined'){
            data.sort(sort_by(jsonKey, true));
         }else{
            data.sort(sort_by(jsonKey, true, callbacks['desc']));
         }
      }
      makeTableBody();
      $("#"+sorted).removeClass("sorted");
      $("#"+sorted).addClass("sorter");
      $(this).addClass("sorted");
      sorted = $(this).attr('id');
   });
};
/* ソート設定関数    */
var sort_by = function(field, reverse, primer){
   reverse = (reverse) ? -1 : 1;
   return function(a, b){
      a = a[field];
      b = b[field];
      if (typeof(primer) != 'undefined'){
         a = primer(a);
         b = primer(b);
      }
      if (a < b) return reverse * -1;
      if (a > b) return reverse * 1;
      return
   };
};
/* data → table 作成 関数 */
var makeTableBody = function(){
   $(tbodyselector).empty();
   var tbody = $(tbodyselector + ":last");
   for(var i in data){
      $(tbody).append( data[i].trobj );
   }
};


この中の、tableSortInit 関数と asignSort 関数を直接使うことになります。

HTMLが、例えば以下のようあります。

<table id="target">
   <thead>
      <tr>
         <th><a href="#" id="idASC" class="sorted">▲</a> ID <a href="#" id="idDESC" class="sorter">▼</a></th>
         <th><a href="#" id="customerASC" class="sorter">▲</a> 顧客 <a href="#" id="customerDESC" class="sorter">▼</a></th>
         <th><a href="#" id="timeASC" class="sorter">▲</a> 時間帯 <a href="#" id="timeDESC" class="sorter">▼</a></th>
      </tr>
   </thead>
   <tbody>
      <tr><td>1</td><td>ナカノ</td><td>10時~12時</td></tr>
      <tr><td>2</td><td>イシザワ</td><td>15時~17時</td></tr>
      <tr><td>3</td><td>アユム</td><td>13時~15時</td></tr>
      <tr><td>4</td><td>カメヤマ</td><td>10時~12時</td></tr>
      <tr><td>5</td><td>タチカワ</td><td>時間帯なし</td></tr>
      <tr><td>6</td><td>イシグチ</td><td>17時~20時</td></tr>
      <tr><td>7</td><td>ミヤモト</td><td>20時~21時</td></tr>
      <tr><td>8</td><td>ハシモト</td><td>20時~22時</td></tr>
      <tr><td>9</td><td>ノムラ</td><td>時間帯なし</td></tr>
      <tr><td>10</td><td>ウエノ</td><td></td></tr>
   </tbody>
</table>


これに対する指定が以下のようになります。

<script type="text/javascript">
$(function(){
   tableSortInit("#target tbody", "idASC",
      {  "id" : function(tr){ return parseInt($(tr).children("td:nth-child(1)").html()); },
         "customer" : function(tr){ return $(tr).children("td:nth-child(2)").html(); },
         "time" : function(tr){ return $(tr).children("td:nth-child(3)").html(); },
   });

   asignSort('idASC', 'idDESC', 'id');
   asignSort('customerASC', 'customerDESC', 'customer'
      ,{ 'asc'  : function(a){ return a; },
         'desc' : function(a){ return a; },
      }
   );
   asignSort('timeASC', 'timeDESC', 'time'
      ,{ 'asc' : function(a){
                  if (!a.match(/[0-9]/g)){
                     return "24時~24時";
                  }
                  return a;
               },
         'desc' : function(a){ return a; },
      }
   );
});
</script>

表示は以下のとおり。