初めまして、クオンと申します。
最近、ReFUEL4プロジェクトの仕事をしております。
宜しくお願い致します。
今回はKnockout.jsを使って、カラムでソート実装について書こうと思います。
この記事の内容が間違ってたら、ご指摘頂ければ、嬉しいです。
テーブルソートを実装してくれるJquery DataTableプラグインを読んだことがあって、今回はDataTableプラグインのような見た目のあるソートを作ってみようと思います。
DataTableプラグインとは
jQuery DataTablesは大量のデータも高速でフィルタリングしてくれるデータテーブルを実装するスクリプトです。
こちらで参考してください DataTable Plugin
以下は簡単なサンプルです。
ヘッダクリックでテーブルソートを実装してくれます。
ID | Name | |
---|---|---|
123456 | protnc@example.com | System Architect |
234567 | foo@example.com | Accountant |
788886 | hoge@example.com | Junior Technical Author |
593456 | bee@example.com | Tran Ngoc Cuong |
以下はLaravelとKnockoutJSを使って、上記のようなソートを作ってみてみましょう。
作り始め
今回のロジックは以下の通りです。
データベースから取得したUsersのリストをテーブルで表示します。ユーザーにつき、3つのカラムがあります(user_id,email,name).
各カラムをクリックしたら:
- 当時のそのカラムの状態によって、カラムとソート順を取って、AJAXでサーバに値を投げます。
- サーバにソートしてもらいます。
- サーバから返すデータで更新します
各カラムにつき、3つの状態があります。
・waiting : ソートされません(他の項目でソート中)
・sorting_asc 降順にソート中
・sorting_desc 昇順にソート中
Knockout.jsの概要や、どんな感じなのかのサンプルは村上の記事や青山の記事をご覧ください。
では、一緒にやりましょう!!!
CSS
まずは3つの状態のスタイルを作りましょう!
1 2 3 4 5 6 7 8 9 |
.table tr .waiting { background: url('../img/sort_both.png') no-repeat center right !important; } .table tr .sorting_asc { background: url("../img/sort_asc.png") no-repeat center right; } .table tr .sorting_desc { background: url("../img/sort_desc.png") no-repeat center right; } |
ViewModelを作成
ViewModel内に監視対象の値を作成します。
1 2 3 4 5 6 7 8 9 10 |
var UserModel = function() { var self = this; self.users = ko.observableArray(users); self.headers = [ {id: 1, title: 'ID', sortPropertyName: 'id', sorting_asc: ko.observable(false), sorting_desc: ko.observable(false)}, {id: 2, title: ‘Email', sortPropertyName: ‘email', sorting_asc: ko.observable(false), sorting_desc: ko.observable(false)}, {id: 3, title: ’Name', sortPropertyName: ‘name', sorting_asc: ko.observable(false), sorting_desc: ko.observable(true)}, ]; self.activeSort = ko.observable(3); } |
observableArrayを使うと、usersのリストをbindしてくれます。
テーブルのヘッダーをKnockoutに処理させます。
カラムにつきの各属性をKnockoutに値を監視させます。
仮に初期は’name’というカラムで降順にソートすれば、Knockoutのheadersの’name’カラムのsorting_desc値をtrueにして、activeSortを3にします。(3はheadersで’name’の番です。)
HTML
UserのリストとheadersをBindしてくれます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<table class=""> <tr> <th></th> <!-- ko foreach: headers --> <th data-bind="css: {'waiting': $parent.activeSort() !== id, 'sorting_asc': sorting_asc,'sorting_desc': sorting_desc},click: $parent.sort, text: title"></th> <!-- /ko --> </tr> <tbody data-bind="foreach: users"> <tr> <td data-bind="text: user_id"></td> <td data-bind="text: email"></td> <td><a data-bind="text: username"></a></td> </tr> </tbody> </table> |
カラムにつき、上記の3つ状態の値に応じ、CSSのクラスが確定されます。
カラムをクリックすると、sortというobservableが呼び出されます。
次はViewModelにsortとupdateのobservableを作成します。
ViewModelにsortとupdateのobservableを作成
まずはJSファイルにURLのパラメータを持っている変数を定義します。(Ajax用です)
1 2 3 4 5 6 |
// ソートカラム,初期値は'name'カラム urlParams["column"] = urlParams["column"] ? urlParams["column"] : 'name’; urlParams["order"] = urlParams["order"] ? urlParams["order"] : 'desc'; //ページング用 urlParams["offset"] = urlParams["offset"] ? parseInt(urlParams["offset"]) : 0; urlParams["limit"] = 20; |
sortのobservable
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
// theadはクリックされたカラム self.sort = function(thead, event){ // カラムのsorting_asc,sorting_descの値を更新する if(!thead.sorting_asc() && !thead.sorting_desc()) { thead.sorting_asc(true); } else { thead.sorting_asc(!thead.sorting_asc()); thead.sorting_desc(!thead.sorting_desc()); } // activeSort更新 if(thead.id !== self.activeSort) { self.activeSort(thead.id); } // urlパラメータにカラム名とソート順の値を入れる var params = urlParams; params['column'] = thead.sortPropertyName ? thead.sortPropertyName : params['column']; params['order'] = thead.sorting_asc() ? 'asc' : 'desc'; self.update(params, true); return false; }; |
updateのobservable
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
self.update = function(params, history){ // ajaxでdataを投げる var data = $.param({ column: params["column"], order : params["order"], offset : params["offset"], format : "json" }); $.ajax({ url: location.pathname, method: 'GET', contentType: false, processData: false, data: data, error: function(xhr, error) { console.log(error); }, success: function(response) { updating = true; // レスポンスでurl パラーメタをアップデート urlParams["column"] = response["column"]; urlParams["order"] = response["order"]; urlParams["offset"] = response["offset"]; urlParams["limit"] = response["limit"]; // users変数値を更新する self.users(response['users']); updating = false; } }); }; |
PHPのフレームワークLaravelを使います
Ajaxで投げたデータを応じて、処理します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
$listLength = 20; $query = NULL; //パラメータを取得 //パラメータが無い場合は、初期値を設定する $offset = intval(Input::get('offset',0)); $order = Input::get('order', 'desc'); $column = Input::get('column', ’name’); // Userモデル // mysqlでカラムをソートしてくれる $query = User::orderBy($column, $order); // Userテーブルの一部データを取得 // Laravel Collectionオブジェクトを取得 $users= $query->skip($offset)->take($listLength+1)->get(); $hasNext = (count($advertisers) > $listLength); $users = $users->splice(0, $listLength); // // レスポンスを返す if( strtolower(Input::get('format')) === 'json' ) { $result = [ 'hasNext' => $hasNext, 'offset' => $offset, 'limit' => $listLength, 'order' => $order, 'column' => $column, 'users' => [], ]; // ユーザの配列を返す foreach( $users as $user ){ $result['users'][] = [ "id" => $user->id, "name" => $user->name, "email" => $user->email, ]; } return \Response::json($result); } |
サーバに返した処理されたデータによって、上記のupdateのobservableでusers、urlパラメータを更新して、HTMLでBindしてくれます。
それで完成になります。
では、終わりになります。
最後まで読んでいただき、ありがとうございました。
これからも宜しくお願い致します。
システム部で開発させて頂きます。学んだこと、気になることを書こうと思います。