前回は、List.jsのsortメソッドを使って3カラムのソートをやりました。
前回の問題点
3つのカラムを指定してソートできるところまではよかったですが、昇順を指定すると3カラムすべてが昇順になり、降順を指定すると3カラムすべてが降順になってしまいます。今回は、カラムごとにソート優先度とソートの方向を決められるようにしてみます。
実装した内容は、
- 昇順にソートすると、bornとdeptは昇順、nameだけは降順
- 降順にソートすると、bornとdeptは降順、nameは引き続き降順
変更した部分
前回のコードからの変更点です。
1. originalsortのメソッドに、複数のカラム名とソート方向をhashの形式で受け取るようにした
2. 受け取ったhashは、List.jsのsortメソッドに勝手にパラメータを足して渡してみた
3. 元のsortメソッドのvalueNameとorderは使わずに、勝手に足したパラメータでソートした
4. ソートした全カラムにascもしくはdescのclassが付くようにした
修正したコード
<html>
<head>
</head>
<body>
<div id="users">
<table border="1">
<thead>
<tr>
<th class="sort" data-sort="name">Name</th>
<th class="sort" data-sort="born">Born</th>
<th class="sort" data-sort="dept">Dept</th>
</tr>
</thead>
<!-- IMPORTANT, class="list" have to be at tbody -->
<tbody class="list">
<tr>
<td class="name">4</td>
<td class="born">1986</td>
<td class="dept">sales</td>
</tr>
<tr>
<td class="name">3</td>
<td class="born">1986</td>
<td class="dept">marketing</td>
</tr>
<tr>
<td class="name">2</td>
<td class="born">1986</td>
<td class="dept">sales</td>
</tr>
<tr>
<td class="name">1</td>
<td class="born">1983</td>
<td class="dept">marketing</td>
</tr>
<tr>
<td class="name">0</td>
<td class="born">1987</td>
<td class="dept">tech</td>
</tr>
</tbody>
</table>
</div>
<!--ボタンの呼び出し部分で、カラムをとソートの方向を指定。順番関係あり-->
<button onclick="javascript:originalsort({'born':'asc','dept':'asc','name':'desc'});">ASC</button>
<button onclick="javascript:originalsort({'born':'desc','dept':'desc','name':'desc'});">DESC</button><br>
<script src="https://cdnjs.cloudflare.com/ajax/libs/list.js/1.5.0/list.min.js"></script>
<script>
var options = {
valueNames: [ 'name', 'born', 'dept' ],
};
var userList = new List('users', options);
//ここまでは普通にList.js
//ソート用の関数(ボタンから呼び出す)
//引数のhash形式のsortorderは、sortメソッドに渡す。
function originalsort(sortorder){
userList.sort('', {
order: '',
alphabet: undefined,
insensitive: true,
sortFunction: multisort, //callbackの関数を指定
sortDirection:sortorder //勝手に足した
});
setOrderClass(sortorder);
}
//classをつける関数
function setOrderClass(sortorder){
btns = userList.utils.getByClass(userList.listContainer, userList.sortClass);
for (var i = 0, il = btns.length; i < il; i++) {
sort_col_name = userList.utils.getAttribute(btns[i], 'data-sort');
console.log(sort_col_name + ' >>> ' + sortorder[sort_col_name]);
sort = sortorder[sort_col_name];
userList.utils.classes(btns[i]).add(sort);
}
}
//List.jsから呼び出される関数。前回と同じくAとBの大きさを判定するだけ
function multisort(itemA, itemB, option){
console.count("sort count");
//console.log(option);
var ans =0;
//option.sortDirectionでhashが受け取れる
for( d in option.sortDirection ){
ans = userList.utils.naturalSort(itemA.values()[d], itemB.values()[d]);
if( ans == 0){
continue;
}
if( option.sortDirection[d]=='desc'){
ans = ans *(-1);
}
break;
}
console.log('Sort answer =%s', ans);
return ans;
}
</script>
<style>
.sort.desc:after {
content:"▼";
}
.sort.asc:after {
content:"▲";
}
</style>
</body>
</html>
ボタンに仕込んでいる関数の引数で何をどう並べるのか決めています。
javascript:originalsort( {'born':'asc','dept':'asc','name':'desc'} );
最初に指定したカラムが優先で、同一の場合は第二ソートキー、第三ソートキーとなります。ここを変えれば自由に優先度の方向の決められます。
気が付いたこと
1.List.jsのsortの第二引数のhashが自由に使えたこと。
https://github.com/javve/list.js/blob/master/src/sort.js#L60
arguments[1]全体をoptionsに入れているので間違いない。(ただしver.1.5に限る)
2.List.jsのutilには便利な関数が入っていること
getAttribute, classes関数は便利
注意事項
sortDirectionのhashに指定したカラムがない場合、asc/desc以外が指定された場合の挙動は未確認です。たぶん、エラーになると思います。改造してお使いください。