Backbone.jsでデータを扱う
Backbone.ModelとBackbone.Collection
まずは、Backbone.ModelとBackbone.Collectionの説明をしていきます。 2つとも、Webアプリ上でデータを扱う機能です。関係性としては、Backbone.Modelの集合体が、Backbone.Collectionだと考えてください。
Modelでは、基本的には、1レコード(1オブジェクトという言い方がいいかもしれません)のデータを管理します。また、管理するレコードにデータを挿入するときにバリデーションチェック等もこのModelに含んでいます。
Collectionは、前述したとおりModelの集合体だと考えてください。 Modelが1レコード(1オブジェクト)と表現する場合は、Collectionは1テーブルのような形となります。
わかりやすく書いていくと、たとえばTwitterリストを表現したい場合、1ツイートのツイート内容や投稿時間といった1つ1つのデータは、Modelの中に格納されます。Collectionはそのユーザーがツイートした全項目をまとめ上げたものとなります。
ModelとCollectionは、それぞれ前回学んだBackbone.Viewと紐付けることができ、その紐付けられたViewを重ね合わせていって画面を作るということになります。ですので、上のTwitterの画面を作る場合は、ModelのViewは、ツイート単位の列になり、たとえば"返信機能"や"タップしたときに移動する機能"は、そのModelに紐付けたViewのイベントとして書いていく様な形になります。
何となく、想像ついてきましたか? では、実際にModelとCollectionを作っていきましょう。
まずはModelを作っていきます
今回は、前回に引き続き、type IT Academyの講師陣を紹介する画面を管理するデータを作ってみましょう。HTMLの宣言については、前回とほとんど同じですので、前回のソースコードをコピーしてきてもらってもかまいません。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | <!DOCTYPE html> < html lang = "en" > < head > < meta http-equiv = "content-type" content = "text/html; charset=UTF-8" /> < title >type IT Academy</ title > <!--jQueryも併用できるので読み込む--> < script src = "lib/js/jquery-1.10.1.js" ></ script > <!--Backboneの読み込み / underscore.jsに依存--> < script src = "lib/js/underscore.js" ></ script > < script src = "lib/js/backbone.js" ></ script > <!-- 1. --> </ head > < body > <!-- 1. HTMLを書いていきます --> </ body > </ html > |
1.の部分にModel用とCollection用のJSを読み込みます。
1 | < script src = "app.model.thumbnail.js" ></ script > |
記述が終わったら、早速中身を書いていきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | var app = app || {}; app.model = app.model || {}; app.model.thumbnail = Backbone.Model.extend({ defaults: { id: null , name: null , profile: null , favorite: false , worktitle: null , workdesc: null , publish: null , gender: null } }); |
Backbone.Model.extendで拡張したクラスは、グローバル領域からアクセスできるように変数に格納する必要がありますが、他の変数と名前がかぶる可能性もありますので、名前空間を作る形で運用しています。ですので、最初の2行で
1 2 | var app = app || {}; app.model = app.model || {}; |
は、appという名前空間と、app.modelという名前空間を作っていることになります。 フレームワークによっては、名前空間を作れるようなメソッドや、Require.JSの様なさらに高度にクラスとファイル群を管理できるライブラリもありますが、今回は、上記の方法で書いていきます。
Modelのプロパティとしてdefaultsを書きましたが、これは、デフォルト値を宣言するものになります。厳密に型を規定するような仕組みはありませんので(後に説明するvalidateで対応可能ですが)、共同開発者にわかりやすくデフォルトの型を宣言しました。
Modelにデータを入れてみましょう
では、早速このモデルを使っていきましょう。 まずは、defaultsが効いているかを確認するために、index.htmlに下記のコードを書いてください。
1 2 3 4 5 6 | < script type = "text/javascript" > $(document).ready(function(){ var m = new app.model.thumbnail(); console.info(m.toJSON()); }); </ script > |
Modelを起動して、toJSONでJSONに変換して、consoleで表示しています。toJSONは、Modelの中に持っているデータをJSON形式にしてくれるので、非常に便利な機能ですね。
consoleに
1 | Object {id: null , name: null , profile: null , favorite: false , worktitle: null , workdesc: null …} |
と表示されたでしょうか?
次に
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | < script type = "text/javascript" > $(document).ready(function(){ var m = new app.model.thumbnail({ id: 4, name: "野村亮之", profile: "2004年 名古屋市立大学芸術工学部在学中に...", worktitle: "Backbone.jsでクライアントMVCに挑戦!", workdesc: "いまや、Webサービスのクライアント側を司る言語として...", publish: "2013-01-01 00:00:00", gender: "male" }); console.info(m.toJSON()); }); </ script > |
と書いてください。 これで、データを入れ込むことができました。consoleで表示してみると、データとして挿入していない、favoriteなども適切にプロパティとして存在しているのが分かりますね。
Modelにはvalidate機能などもありますが、今回は、データを読み込むことにフォーカスしていますので、割愛します。
Collectionで、Modelをまとめる
全体像が見えるように、Collectionの話をしていきましょう。冒頭に書いたとおり、CollectionはModelの集合体です。では、上記のModelを使って、Collectionを作っていきましょう。
新しいファイルを作っていきます。index.htmlにscriptの宣言をします。 modelを指定しますので、必ず、app.model.thumbnail.jsの後で読み込んでください。
1 | < script src = "app.collection.thumbnail.js" ></ script > |
app.collection.thumbnail.jsに下記のプログラムを書きます。
1 2 3 4 5 6 | var app = app || {}; app.collection = app.collection || {}; app.collection.thumbnail = Backbone.Collection.extend({ model: app.model.thumbnail }); |
modelプロパティに先ほど作成したapp.model.thumbnailを記します。 ここは、文字列として渡すのではなく、生成したオブジェクトをそのまま渡す形です。
ですので、上述のようにあらかじめModelを作成しておく必要があります。
さっそく、ブラウザで実行してみましょう。 先ほどModelの起動をした部分をそのまま下記のプログラムに置き換えてみます。
1 2 3 4 5 6 | < script type = "text/javascript" > $(document).ready(function(){ var m = new app.collection.thumbnail(); console.info(m.toJSON()); }); </ script > |
consoleを確認すると、[]とだけ、表示されましたでしょうか? 当然レコードデータは挿入していないので、ただの配列が出力されます。
Collectionにデータを挿入する
実際にデータを入れていきましょう。 引数として配列を与えることにより、データの挿入ができます。後から追加したい場合は、addを使います。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | var m = new app.collection.thumbnail([ { id: 4, name: "野村亮之" , profile: "2004年 名古屋市立大学芸術工学部在学中に..." , worktitle: "Backbone.jsでクライアントMVCに挑戦!" , workdesc: "いまや、Webサービスのクライアント側を司る言語として..." , publish: "2013-01-01 00:00:00" , gender: "male" }, { id: 1, name: "鈴木理恵子" , profile: "株式会社ミクシィ 技術部 コアプロダクト開発G所属..." , worktitle: "Noコーディング?!誰でもかんたんBaaS入門" , workdesc: "BaaS(Mobile BaaS、MBaaS等とも呼ばれます)という言葉を..." , publish: "2013-01-01 00:00:00" gender: "female" } ]); |
これで、Collectionができました。通信で取得したJSONなどもそのままCollectionに入れてしまえば、利用できるのが分かりますね。
ちなみに、Collectionにある、urlとparseを利用することにより、サーバから取得したデータをそのまま追加することもできます。
Collectionには、そのほか、push, pop, unshift, shift, slice, lengthなど、JavaScriptの配列操作でおなじみのメソッドが用意されていますので、一度リファレンスをみてみましょう。
CollectionとModelを画面に反映する
Backbone.jsで扱うことのできるデータを作ってきましたが、ここからは、そのデータを画面で表示する方法を見ていきましょう。Backbone.ViewにModelとCollectionを結びつけることにより表示をしていきます。
Model用のViewをつくる
前回は、静的HTMLをBackbone.Viewに結びつけて操作をすると言うことを実践しました。 下記のような形です。
1 2 3 4 5 6 7 | var Thumbnail = Backbone.View.extend({ //このViewが制御したい最上位のHTMLを指定する(CSSセレクタで指定) el: '.thumbnail' , //... }); |
elプロパティで、対象のクラスを指定することにより実現していました。 今回は、次のように書いていきます。
先ほどと同じように、新たにファイルを作成し
1 | < script src = "app.view.thumbnail.js" ></ script > |
中身を次のようにします。
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 | var Thumbnail = Backbone.View.extend({ tagName: 'div', attributes: { style: 'width: 210px;', class: 'span4 card thumbnail', }, //1. template, renderを書いていきます template: _.template([ '< div >', '< img src="images/<%= id %>.png">', '< div class = "text-center" ><%= name %></ div >', '< div class = "caption" >', '< h3 ><%= worktitle %></ h3 >', '< p ><%= workdesc %></ p >', '</ div >', '</ div >' ].join('')), render: function(){ this.$el.html(this.template(this.model.toJSON())); return this; } }); |
index.htmlの中身を下記のように書き換えてください。
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 | < script type = "text/javascript" > $(document).ready(function(){ var m = new app.collection.thumbnail([ { id: 4, name: "野村亮之", profile: "2004年 名古屋市立大学芸術工学部在学中に...", worktitle: "Backbone.jsでクライアントMVCに挑戦!", workdesc: "いまや、Webサービスのクライアント側を司る言語として...", publish: "2013-01-01 00:00:00" }, { id: 1, name: "鈴木理恵子", profile: "株式会社ミクシィ 技術部 コアプロダクト開発G所属...", worktitle: "Noコーディング?!誰でもかんたんBaaS入門", workdesc: "BaaS(Mobile BaaS、MBaaS等とも呼ばれます)という言葉を...", publish: "2013-01-01 00:00:00" } ]); _.each(m.models, function(v){ $(document.body).append(new app.view.thumbnail({model: v}).el); }, this); }); </ script > |
これを実行すると、下記のようにHTMLが表示されるはずです。
どうでしょう、うまくHTMLが表示されたでしょうか?
では、1つずつ解説をしていきましょう。まずは、app.view.thumbnailの中身についてです。
tagNameとattributes
tagNameは、そのViewのルートタグを指します。また、attributesはオブジェクトを指定することができて、そのルートタグのclass, styleなどを上記の様に指定していくことができます。
renderとtemplate
templateには、このViewの中身のHTMLを書いていきます。通常は、_.template(Underscore.jsのTemplate機能)を利用して、書いていきます。Modelのプロパティ名をのようにして、埋め込むことができます。
Underscore.jsのテンプレート機能は、結構強力な機能を持っているので、単独でも利用を検討してもいいかもしれません。
renderは、生成されたルートタグの中に実際にHTMLを書いていくために実行されます。
1 | this .$el.html( this .template( this .model.toJSON())); |
通常は、上記の様にルートタグの中にHTMLを描画する形にします。補足になりますが、this.$elは、jQuery Element形式で、ルートタグを取得する方法です。
Collection用のViewをつくる
前項で、Collection.modelsを利用して、ModelとViewを使って、表示してみましたが、CollectionとViewを使ってもっと統合された形でHTMLを出力してみます。
1 2 3 | _.each(m.models, function (v){ $(document.body).append( new app.view.thumbnail({model: v}).el); }, this ); |
をCollectionと紐付ける中に入れていきます。
新たにファイルを作成し
1 | < script src = "app.view.thumblist.js" ></ script > |
index.htmlで読み込みます。先ほど読み込んだ、app.view.thumbnail.jsの後に書いてみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | var app = app || {}; app.view = app.model || {}; app.view.thumblist = Backbone.View.extend({ tagName: 'div' , attributes: { class: 'row-fluid' }, render: function (){ this .collection.each( function (v){ this .$el.append( new app.view.thumbnail({model: v}).render().el ); }, this ); return this ; } }); |
もう、見慣れてきましたね。model用のViewと同じように、tagName, attributesを指定します。renderでは、このクラスで扱うcollectionを順に描画して、自分自身の子要素として追加をしています。
これを実行するには以下の通りです。
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 | < script type = "text/javascript" > $(document).ready(function(){ var m = new app.collection.thumbnail([ { id: 4, name: "野村亮之", profile: "2004年 名古屋市立大学芸術工学部在学中に...", worktitle: "Backbone.jsでクライアントMVCに挑戦!", workdesc: "いまや、Webサービスのクライアント側を司る言語として...", publish: "2013-01-01 00:00:00" }, { id: 1, name: "鈴木理恵子", profile: "株式会社ミクシィ 技術部 コアプロダクト開発G所属...", worktitle: "Noコーディング?!誰でもかんたんBaaS入門", workdesc: "BaaS(Mobile BaaS、MBaaS等とも呼ばれます)という言葉を...", publish: "2013-01-01 00:00:00" } ]); var v = new app.view.thumblist({ collection: m }); $(document.body).append(v.render().el); }); </ script > |
最後の部分が、完結になりました。また、Collection用のViewで生成した要素をBody要素に追加しています。実行された見た目はあまり変わりありませんが、div.row-fluidの中に、model用のViewで生成されたdiv要素が描画されます。
いかがでしたでしょうか? これで、Backboneの主要機能であるModelとCollection、それと前回からのViewを組み合わせて動的に画面を描画できるようになりました。
SEOを聞かせなければならないサービス等では、第1回目でお伝えしたような方法のほうがよいですが、ツール・ユーティリティ系または、業務系のアプリケーションの場合は、サーバとの通信をAjaxにまとめ、JSONでやりとりするところに集中させ、描画部分をJavaScriptですべて生成する場合に今回の方法が使えます。
自分のサービスを構築する際に、是非Backboneの導入を検討してみてください。第3回は、今までお伝えしたことを踏まえ、簡単なツール系アプリを作ってみます。