とある角度から

お腹いっぱいたべられる幸せ

backbone.jsでtodoアプリを少しずつ作る(1)

まえおき

backbone.jsのtodoサンプルなんて、いまどきどこにでも転がっています。
でも、そのサンプルを参考に作ってみたけど、いまいち理解が深まらない。。。

という「自分」のために一歩ずつ理解を深めながら、もう一度todoサンプルを作っていこうと思います。

完成系

やってる内容はtodoアプリそのままですが、登録するものを「食べ物の名前」と「カロリー」にしてます。

下準備

backbone.jsはjqueryとunderscore.jsに依存します。
また、今回はデータをlocalStorageに保存します。これにはbackbone.localStorageプラグインを使用します。

まずはgithubより、backbone.js関連のファイルを取得します。
% git clone https://github.com/documentcloud/backbone.git

test/venderフォルダ内のライブラリから必要なものを取得し、以下のファイル構成で配置します。

ファイル構成
index.html (自分で作る)
js
 - page-index.js (自分で作る)
 - lib
    - backbone.js
    - backbone.localStorage.js
    - jquery.js
    - underscore.js

index.htmlとpage-index.jsは以下の内容。

index.html
page-index.js

これで下準備は完了です。

モデルの設計と実装

まずはどんなデータを扱うかを考えます。
今回は食べ物とカロリーのセットなので、入力データ1つの構造はシンプルにこんな感じ

Food: {
  name: "名前"
  calory: "カロリー"
}

これをModel化して、さらにCollectionを作ってみます。
※超ざっくり説明ですが、DBに例えるとModelはテーブル構造の定義で、Collectionが実際のテーブルみたいなものです。

page-index.js note02Foodモデルでは、デフォルト値の設定と初期化処理を定義し、これをベースにFoodCollectionコレクションを定義しています。

また、最後の2行でテストデータを登録しています。実際にlocalStorageの中を見るとこんな感じです。

f:id:n_1010real:20140522112809p:plain

※backbone.localStorage.jsは読み込むだけで、データの保存・読込を勝手にlocalStorageに向けてくれます。べんり

ビューの設計

次に登録したデータを表示するViewを作っていきます。
がその前にビューを設計していきます。

ここでいうビューの設計は、「どのようにビューを分割するかを決めること」です。

以下のような単位で、Viewを分割していきます。

・ページ内の構成による分割(header,footer等で分ける)
・機能的な分割(検索フォームと検索結果で分ける)
・よく繰り返すパーツを部分的に分割(検索結果内の1項目を別Viewにする)

結果こんな感じに分割してみました。

AppView : ページ全体を制御
 - NewView : 食べ物の新規登録部分
 - FoodListView : 登録された食べ物のリスト表示部分
    - FoodView : リスト内の食べ物1件

データを表示

ではまず、既に登録されたデータを表示するだけのViewを書いてみます。
page-index.js note03先程のテストデータ登録はコメントアウトして、その下にViewを追加します。
各Viewの中身は以下の通り

AppView

FoodListViewのインスタンス生成と、コレクションに対するイベントハンドラの設定+初期読込をしてます。

FoodListView

このビューで扱うDOM要素をelに指定します。(ビューとDOMを紐つける感じ)
初期化の際に、ul要素をDOMに追加します。
また、食べ物が1件追加されたときに、FoodViewインスタンスを生成し、ul内に1件DOMを追加します。
addAllが呼ばれた際には、コレクション全てを走査して、それぞれについてaddを行います。

FoodView

elの変わりに、tagNameとclassNameを指定します。指定したtagNameとclassNameのタグがelに設定されます。
初期化時に自身に割り当てられたModelからDOMを生成し、elに設定します。

※新規登録用のView(NewView)は今回はまだ手を付けてません。

結果はこちら
f:id:n_1010real:20140522182952p:plain
localStorageのデータがリスト表示されます。

データを手動で登録してみる

ここで以下を「var App = new AppView;」の下に追加してみましょう。

  // test
  window.fc = fc;

そして、consoleに「fc.create({name:'cakes', calory:300});」と入力してEnter。
結果はこちら
f:id:n_1010real:20140522190133p:plain
データが追加されたと同時に、リストに情報が追加されました。

AppView内で、Collectionへデータを登録した際に、foodlist.addを呼び出しているので当たり前といえば当たり前です。
ただ、ここで重要なのは、「データを登録するだけで、リストの更新ができる」ことが確認できたことです。

逆に言えば、「新規登録部分は、データを登録さえすれば良く、リストの更新は考えなくて良い」ので、
新規登録部分とリスト表示部分を完全に切り離して考えることができます。
このように、各Viewが疎結合になる様に設計していくことで、複数人による分散開発がより容易になります。

新規登録部分を作る

新規登録用のNewViewを実装していきます。とこんな感じ
page-index.js note047-9行:#newfood-buttonなbuttonがclickされたらaddFoodを呼び出すようにしてます。
このようにBackbone.View.eventsプロパティに対して、'イベント名 要素(セレクタ)':'関数名'と指定することで、特定のイベントに動作を割り当てることができます。
16-19行:データを登録した後に、自分自身を再描画しています。
30行:AppViewの初期化時にNewViewのインスタンスを生成します。

結果はこちら
f:id:n_1010real:20140522195102p:plain
FoodViewやFoodListViewと完全に切り離して開発することができました。

編集・削除機能を追加する

FoodViewにロジックを追加していきます。

page-index.js note057-8行:FoodViewに紐付けられたmodelに変更があった場合に呼び出す関数を指定しています。(Backbone.View.removeはデフォルトで定義されています)
11-15行:要素に対するイベントに対して、動作を割り当てています。
26-34行:編集用に要素を再設定します。食べ物の名前がダブルクリックされた際に呼ばれます。
35-40行:Enterが押されたときに、modelを更新します。
41-44行:modelを破棄します。

結果はこちら(ページの最初のものと同じ)

これで、一応todoアプリ的な物が完成しました。

まとめ

途中から感じたかもですが、Viewを細かく切り離した結果、機能を追加するときに、他のViewを意識しなくて良くなりました。
また、他のViewの変更は基本的にmodelの変更を介して行われるため、各Viewを編集するときにはmodelとのやり取りだけ気にすれば大丈夫です。
モジュールとして分割できるため、複数人での開発もより容易になりますね。

次へ進む

より、MVCぽく修正した感じがこちら↓
backbone.jsでtodoアプリを少しずつ作る(2) - 1010realのブログ ver2