Backbone.jsで簡単なチャットを作ってみる
MVCモデルなjavascriptフレームワークBackbone.jsで超簡単なチャットを作ってみる。
とりあえずものは試しってことでかなり適当な実装だけど勘弁。バックエンドはGAE。
デモ(動作するのはchromeだけっぽい):http://ninsoeki-lab.appspot.com/ (現在停止中)
HTML
まず最初はHTMLを作る。backbone.jsを動かすためにはjQueryとunderscore.jsが必要。
<!DOCTYPE HTML> <html> <head> <meta charset="UTF-8"> <title>Simple Chat</title> <link type="text/css" href="/css/main.css" media="all" rel="stylesheet"/> <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script> <script type="text/javascript" src="http://documentcloud.github.com/underscore/underscore-min.js"></script> <script type="text/javascript" src="http://documentcloud.github.com/backbone/backbone-min.js"></script> </head> <body> <div id="container"> <div id="chatArea"></div> <form method="POST" id='chatForm' name="newMessage" onsubmit="return false"> <input name= 'newMessageString' type="text" /> <br/> <input type="submit" value='send'/> </form> </div> </body> <script type="text/javascript" src="/js/application.js"></script> </html>
今回はテンプレートは使ってないけど、大体の雰囲気は公式デモのコードを見るとわかるね。
<script type="text/template" id="stats-template"> <% if (total) { %> <span class="todo-count"> <span class="number"><%= remaining %></span> <span class="word"><%= remaining == 1 ? 'item' : 'items' %></span> left. </span> <% } %> <% if (done) { %> <span class="todo-clear"> <a href="#"> Clear <span class="number-done"><%= done %></span> completed <span class="word-done"><%= done == 1 ? 'item' : 'items' %></span> </a> </span> <% } %> </script>
Javascript
まずメッセージを保持するモデルを作る。
var Message = Backbone.Model.extend({});
constructor/initializeも定義できるけど、とりあえずこれだけでOK。
このモデルを格納するコレクションを作る。
urlプロパティを定義するとcreateはPOSTで、readはGETでそこにアクセスしてくれる。
var MessageStore = Backbone.Collection.extend({ model: Message, url: function() { return window.document.URL + 'messages'; } }); var messages = new MessageStore;
submitされたときのハンドラー、レンダーをViewに定義。
あんまMVCっぽくないけど・・・。
var ProductView = Backbone.View.extend({ events: {'submit #chatForm' : 'handleNewMessage' }, handleNewMessage: function(data) { var inputField = $('input[name=newMessageString]'); messages.create({ content: inputField.val() }); inputField.val(''); }, render: function() { var that = this; var result = '' messages.each(function(e, idx) { var template = ''; if (idx % 2 === 1) { template = '<p class="top">' + e.get('content') + '</p>'; }else { template = '<p>' + e.get('content') + '</p>'; } result += template.html(); }); $('#chatArea').html(result); return this; } });
createが成功したときの処理をバインド。
messages.bind('add', function(message) { messages.fetch({ success: function(){ view.render(); } }); });
elで指定された要素にrenderの結果が反映されることになる。
今回はあんまり関係ない。
var view = new ProductView({ el: $('#container') });
以上。
application.js
var Message = Backbone.Model.extend({}); var MessageStore = Backbone.Collection.extend({ model: Message, url: function() { return window.document.URL + 'messages'; } }); var messages = new MessageStore; messages.bind('add', function(message) { messages.fetch({ success: function(){ view.render(); } }); }); var ProductView = Backbone.View.extend({ events: {'submit #chatForm' : 'handleNewMessage' }, handleNewMessage: function(data) { var inputField = $('input[name=newMessageString]'); messages.create({ content: inputField.val() }); inputField.val(''); }, render: function() { var that = this; var result = '' messages.each(function(e, idx) { var template = ''; if (idx % 2 === 1) { template = '<p class="top">' + e.get('content') + '</p>'; }else { template = '<p>' + e.get('content') + '</p>'; } result += template + '\n'; }); $('#chatArea').html(result); return this; } }); var view = new ProductView({ el: $('#container') }); messages.fetch({ success: function(){ view.render(); } }); setInterval(function(){ messages.fetch({ success: function(){ view.render(); } }); },10000)
Python(GAE)
GET/POSTの処理を行うだけ。
class Message(db.Model): content = db.StringProperty(required = True) date = db.DateTimeProperty(auto_now_add = True) class MessageHandler(RequestHandler): def post(self): json = simplejson.loads(self.request.form.get('model')) content = json['content'] message = Message(content = content) message.put() return Response('') def get(self): response = Response() response.headers['Content-Type'] = 'application/json' contents = [] query = db.GqlQuery("SELECT * FROM Message ORDER BY date DESC LIMIT 10") for i in query: c = {'content' : i.content} contents.append(c) response.data = simplejson.dumps(contents) return response