概要
knockoutjsでwebsocket-railsをつかったので、導入した手順と、つまづいた点を紹介します。
つくったのは、ユーザーに紐づくタスクリストの「追加・編集・削除・完了」みたいなのが全クライアントに反映されるやつです。
データ的には、以下の様な感じです。ユーザーは何人かいます。
user: [{
id: 1,
name: aaaa,
todo: [
{id: 1, name: aaaaaaa, del: 1},
{id: 2, name: eeee, del: 1},
{id: 3, name: ccccc, del: 0},
{id: 4, name: hhhhh, del: 0},
{id: 5, name: kkkkk, del: 0},
]
},
{
id: 2,
name: aaaa,
todo: [
{id: 6, name: jjj, del: 1},
{id: 7, name: ee, del: 1},
{id: 8, name: gggg, del: 0},
]
},
{
id: 3,
name: aaaa,
todo: [
{id: 9, name: aaaaaaa, del: 1},
{id: 10, name: eeee, del: 1},
{id: 11, name: ccccc, del: 0},
{id: 12, name: hhhhh, del: 0},
]
}]
websocket-railsを導入する
以下の記事を参考にしました。基本的には、手順通りやれば問題ないはずです。
簡単にまとめると、以下の5手順で完了します。
- websocket-railsのgemいれる
- event.rbでコントローラーをマッピング
- JSでマッピングしたルートにデータ送信
- Railsで受け取り、すべてのクライアントに送信
- JSでイベントをバインドし、受け取ったデータを好きに処理する
JS側で配列処理をする
タスクをko.observableさせたいので、該当するデータを、しかるべき配列の中につっこまないといけません。ここが慣れていなかったので戸惑いました。以下ソースです。
削除の処理
// todo_destroyイベントを取得
// dispatcherは「new WebSocketRails("ws://ホスト/websocket");」で、グローバルです。
dispatcher.bind('todo_destroy', function (removedTodo) {
$.each(view_model.users(), function() {
this.todo.remove(function(item) {
// itemはobservableなのでitem.id()とする(http://qiita.com/okmttdhr/items/a180b96b5e5e1b30aa1c)
// idが同じtodoを配列から削除
return item.id() == removedTodo.id
});
});
});
編集の処理
完了もこれと同じような感じです。
// todo_updateイベントを取得
dispatcher.bind('todo_update', function (updatedTodo) {
$.each(view_model.users(), function() {
// 更新の際はremoveのように便利なメソッドがないので(あったら教えて下さい)、eachをネストさせてusersのtodoの中身を見る。
$.each(this.todo(), function(i, item) {
// itemはobservableなのでitem.id()とする(http://qiita.com/okmttdhr/items/a180b96b5e5e1b30aa1c)
// itemはobservableなのでitem.name(updatedTodo.name)のように更新する
// idが同じtodoに対して更新
if(item.id() == updatedTodo.id) item.name(updatedTodo.name);
});
});
});
追加の処理
function TodoConf(data) {
var self = this;
self.id = ko.observable(data.id);
self.name = ko.observable(data.user_id);
self.del = ko.observable(data.completed);
}
// todo_createイベントを取得
dispatcher.bind('todo_create', function (newTodo) {
// pushしたデータもobservableにしたいので、生のデータを一度observableに変換する
var newTodo = new TodoConf(newTodo);
$.each(view_model.users(), function() {
// user_idが同じuserに対してtodoを配列に追加
if (this.id() == newTodo.user_id()) {
this.todo.push(newTodo);
};
});
});
まとめ
knockoutjsっぽいことといえば、observableにするために配列どうするか考えたことくらいでしょうか。
websocketは案外難しくなく、リアルタイムでDOMをただしく反映するということの方が、複雑になればなるほど難しくなってゆくのかなと思いました。とりあえず、jQueryでやらなくてよかったです。。