コンポーネントにデータを持たせる
2015/06/07
前回は、Cape.JS を Ruby on Rails に組み込む手順を解説しました。
今回のテーマは、コンポーネントとデータの関係です。
私たちの目標は、簡単な Web アプリケーション「Todo リスト」の開発です。このアプリケーションは、「タスク(やらなくてはいけないこと)」の集合を扱います。このようなデータはオブジェクトの配列として表現するのがいいでしょう。
ここでいう「オブジェクト」とは、JavaScript のオブジェクトのことです。JavaScript のオブジェクトは、Ruby のハッシュ(連想配列)の性質を持っています。例えば、obj = { x: 1, y: 2 }; obj["z"] = 3
のように書けば、3個のプロパティと値のペアを持つオブジェクト obj
ができます。obj["z"]
は obj.z
とも書けます。
個々のタスクを例えば次のようなオブジェクトとして表すことにします:
{ title: "猫のえさを買う。", done: false }
そして、オブジェクトの配列が「タスクリスト」になります。
[
{ title: "猫のえさを買う。", done: false },
{ title: "歯医者に行く。", done: true }
]
ところで、本題に入る前に Cape.JS をアップデートする方法を紹介しておきましょう。
本日(2015/06/07)、Cape.JS 1.1.0 がリリースされました。なるべく最新のものを使うべきなので、「Todo リスト」の Cape.JS も上げておきましょう。
テキストエディタで bower.json
を開き、
"capejs": "~1.0.0",
を次のように書き換えます。
"capejs": "~1.1.0",
そして、ターミナルで bower install
を実行します。
では、Cape.JS のコンポーネントにタスクの配列を持たせてみましょう。テキストエディタで app/assets/javascripts/todo_list.es6
を次のように書き換えてください。
class TodoList extends Cape.Component {
init() {
this.tasks = [
{ title: "猫のえさを買う。", done: false },
{ title: "歯医者に行く。", done: true }
];
this.refresh();
}
render(m) {
m.ul(m => {
this.tasks.forEach(task => {
m.li(m => {
m.label(m => {
m.input({ type: 'checkbox', checked: task.done }).sp();
m.span(task.title);
});
});
});
});
}
}
コンポーネントクラスに init
という名前のインスタンスメソッドを定義すると、コンポーネントがマウントされた直後にこのメソッドが実行されます。
ここでは tasks
というプロパティにタスクの配列をセットしています。メソッドの末尾で refresh
メソッドを呼び出しています。このメソッドはコンポーネントに対して再描画を指示します。その結果、render
メソッドが呼ばれて、ブラウザの画面が書き換わります。コンポーネントに init
メソッドが存在しない場合は、暗黙裏に this.refresh()
が呼ばれますが、init
メソッドを定義した場合には、その中で this.refresh()
を呼ばないとコンポーネントをマウントしてもブラウザの画面に何も現れませんので注意してください。
Cape.JS は init
メソッドの後で常に this.refresh()
を呼び出さないのでしょうか。それは、init
メソッドの中で Ajax コールが行われてデータの初期化が行われることを想定しているからです。Ajax コールはその名の通り「非同期(synchronous)」ですから、それが完了するのは init
メソッドの実行が終わった後になります。したがって、init
メソッドの後で this.refresh()
を呼び出しても肝心のデータが整っていないことになってしまうのです。この辺りの事情については、この連載が進むにつれて次第に明らかになるでしょう。
render
メソッドの中身も大きく変化しています。配列 this.tasks
に対して forEach
メソッドを呼び出して、ループ処理を行っています。パラメータ task
には { title: "猫のえさを買う。", done: false }
のようなオブジェクトが順にセットされます。そして、この task
の値を参照してチェックボックスとテキストを生成します。
m.input({ type: 'checkbox', checked: task.done }).sp();
m.span(task.title);
JavaScript では task["title"]
の代わりに task.title
と書ける点に注意してください。
では、うまく動くかどうか試してみましょう。ブラウザをリロードして、次のような画面が表示されれば OK です。
だいぶアプリケーションらしくなってきましたね。今回はここまで。次回は、Ajax を利用してコンポーネントのデータを初期化する方法について解説します。