Backbone.js を勉強した時のメモ。
#Backbone.js とは
CoffeeScript, Underscore.js などの作者である Jeremy Ashkenas が作っている JavaScript フレームワーク(jashkenas/backbone | Github)。
クライアントサイドで MVC を実装するための下地(骨組み)を提供する。
Angular.js がフルスタックで様々な機能が用意されているのに対して、 Backbone.js はあくまで Backbone(背骨)であり、骨組みを用意するのみ。
双方向のデータバインディングなどの機能はない。
肉付けをするのは、プログラマのお仕事。
機能が少ない分、覚えることは Angular.js に比べれば少ない、と思う。
#Hello World
##用意するファイル
###Backbone.js
http://backbonejs.org/#
本体。これがないと始まらない。
###Underscore.js(必須)
http://underscorejs.org/
Backbone.js は Underscore.js に依存している。
1.5.0 以上を導入する必要がある。
###jQuery(ほぼ必須)
http://jquery.com/
View および Router を使う場合は必要になるっぽい。
###json2.js(任意)
https://github.com/douglascrockford/JSON-js
古い IE (8 以下)とかで動かす場合に必要になるっぽい。
今回は使わない。
##HTML ファイル
<!DOCTYPE html>
<html>
<head>
<script src="underscore-min.js"></script>
<script src="jquery-2.1.1.min.js"></script>
<script src="backbone-min.js"></script>
<script src="script.js"></script>
</head>
<body>
</body>
</html>
##Model の Hello World
var MyModel = Backbone.Model.extend({
method: function() {
console.log('Hello Model!!');
}
});
var myModel = new MyModel();
myModel.method();
Hello Model!!
##Collection の Hello World
var MyCollection = Backbone.Collection.extend({});
var myCollection = new MyCollection([
{name: 'hoge'},
{name: 'fuga'}
]);
myCollection.each(function(e, i) {
console.log('[' + i + '] ' + e.get('name'));
});
[0] hoge
[1] fuga
##View の Hello World
$(function() {
var MyView = Backbone.View.extend({
render: function() {
this.$el.text('Hello View!!');
return this;
}
});
var myView = new MyView();
$('body').append(myView.render().el);
});
#Model
##基本操作
###Model を作成する
var MyModel = Backbone.Model.extend();
var myModel = new MyModel();
- Model を作成するには、
Backbone.Model.extend()
を使う。 -
extend()
の引数に、インスタンスメンバーの定義を渡す。 - 戻り値はコンストラクタ関数になっていて、
new
でインスタンスを生成できる。
###インスタンスメソッドを定義する
var MyModel = Backbone.Model.extend({
instanceMethod: function() {
console.log('instance method');
}
});
var myModel = new MyModel();
myModel.instanceMethod();
instance method
###コンストラクタを定義する
var MyModel = Backbone.Model.extend({
constructor: function() {
console.log('constructor');
}
});
var myModel = new MyModel();
constructor
-
constructor
という名前のインスタンスメソッドを定義すると、インスタンス生成時に実行される。 -
initialize
という名前でもいい。 -
constructor
とinitialize
を両方定義すると、constructor
の方が実行される。 - 後述する、既存の DOM を関連付ける場合は
initialize
で定義する。- DOM と紐付ける処理が
constructor
のデフォルト処理になっているようで、constructor
という名前で定義(オーバーライド)するとそのデフォルトの処理が実行されなくなる。
- DOM と紐付ける処理が
###static メンバーを定義する
var MyModel = Backbone.Model.extend({}, {
staticField: 'static field',
staticMethod: function() {
console.log('static method');
}
});
console.log(MyModel.staticField);
MyModel.staticMethod();
static field
static method
-
extend()
メソッドの第二引数に渡したオブジェクトが static メンバーになる。
###プロパティを設定・取得する
var MyModel = Backbone.Model.extend();
var myModel = new MyModel();
myModel.set('value', 'field value');
console.log(myModel.get('value'));
field value
-
set(<名前>, <値>)
で値を設定。 -
get(<名前>)
で値を取得。
###プロパティのデフォルト値を設定する
var MyModel = Backbone.Model.extend({
defaults: {
value: 'default value'
}
});
var myModel = new MyModel();
console.log(myModel.get('value'));
default value
###コンストラクタの引数でプロパティを設定する
var MyModel = Backbone.Model.extend();
var myModel = new MyModel({value: 'VALUE'});
console.log(myModel.get('value'));
VALUE
###プロパティを持つかどうかを確認する
var MyModel = Backbone.Model.extend({
defaults: {
value: 'VALUE'
},
method: function() {}
});
var myModel = new MyModel();
console.log(myModel.has('value'));
console.log(myModel.has('xxxxx'));
console.log(myModel.has('method'));
true
false
false
-
has(<名前>)
で、指定した名前のプロパティが存在するかどうかを確認できる。 - メソッドの存在は確認できない。
###プロパティを削除する
var MyModel = Backbone.Model.extend({
defaults: {
value: 'VALUE'
}
});
var myModel = new MyModel();
console.log(myModel.get('value'));
myModel.unset('value');
console.log(myModel.get('value'));
VALUE
undefined
###プロパティを全て取得する
var MyModel = Backbone.Model.extend({
defaults: {
value: 'VALUE'
}
});
var myModel = new MyModel();
var properties = myModel.attributes;
console.log(properties.value);
properties.value = 'changed';
console.log(myModel.get('value'));
VALUE
changed
-
attributes
で全プロパティをオブジェクトで取得できる。 - このオブジェクトの値を変更すると、元のインスタンスのプロパティも書き換わる。
###プロパティのコピーを取得する
var MyModel = Backbone.Model.extend({
defaults: {
value: 'VALUE'
}
});
var myModel = new MyModel();
var properties = myModel.toJSON();
console.log(properties.value);
properties.value = 'changed';
console.log(myModel.get('value'));
VALUE
VALUE
-
toJSON()
でも同じようにプロパティを取得できる。 - ここで取得したオブジェクトは、元のインスタンスが持つ attributes のコピーになる。
- このオブジェクトのプロパティを変更しても、元のインスタンスに影響は与えない。
- ただし、プロパティがさらにオブジェクトの場合、そのオブジェクトは元のインスタンスも参照しているので、変更すれば影響を与える。
###バリデーションメソッドを定義する
var MyModel = Backbone.Model.extend({
validate: function(attrs) {
if (!attrs.value) {
return 'value is empty.';
}
}
});
var myModel = new MyModel({value: 'xxxx'});
console.log(myModel.isValid());
true
-
validate
という名前のインスタンスメソッドを定義する。- 引数に全プロパティをもつオブジェクトが渡される。
- エラーが無い場合は、何も返さないようにする。
- エラーが有る場合は、エラー情報を持つ任意の値を返す。
-
isValid()
メソッドを実行するとvalidate()
が実行され、エラーの有無が boolean で返される(エラーなし =true
)。
####エラー情報を参照する
var MyModel = Backbone.Model.extend({
validate: function(attrs) {
return 'error info';
}
});
var myModel = new MyModel();
myModel.isValid();
console.log(myModel.validationError);
error info
-
validate()
メソッドが返したエラー情報は、validationError
プロパティに保存されている。
###インスタンスのコピーを作成する
var MyModel = Backbone.Model.extend();
var original = new MyModel({
value: {
name: 'Hoge'
}
});
var copy = original.clone();
console.log(copy.get('value').name);
copy.get('value').name = 'xxxx';
console.log(original.get('value').name);
Hoge
xxxx
-
clone()
メソッドでインスタンスのシャローコピーを作成できる。
###値が書き変えられたプロパティを取得する
var MyModel = Backbone.Model.extend();
var myModel = new MyModel({
value: 'VALUE'
});
myModel.set('value', 'change');
console.dir(myModel.changed);
value "change"
-
changed
に変更されたプロパティの情報が保存されている。
###プロパティが変更されたかどうかを確認する
var MyModel = Backbone.Model.extend();
var myModel = new MyModel({
value: 'VALUE'
});
console.log(myModel.hasChanged('value'));
myModel.set('value', 'change');
console.log(myModel.hasChanged('value'));
false
true
##Underscore.js のメソッドを使う
Model インスタンスには、 Underscore.js が提供している一部の関数がメソッドとして定義されている。
###全てのプロパティの名前をリストで取得する
var MyModel = Backbone.Model.extend({
defaults: {
value: '',
name: ''
}
});
var myModel = new MyModel();
console.log(myModel.keys());
["value", "name"]
###全てのプロパティの値をリストで取得する
var MyModel = Backbone.Model.extend({
defaults: {
value: 'Value',
name: 'Name'
}
});
var myModel = new MyModel();
console.log(myModel.values());
["Value", "Name"]
###指定した名前のプロパティだけを抽出する
var MyModel = Backbone.Model.extend({
defaults: {
value: 'Value',
name: 'Name'
}
});
var myModel = new MyModel();
console.log(myModel.pick('value'));
Object { value="Value"}
###指定した名前以外のプロパティだけを抽出する
var MyModel = Backbone.Model.extend({
defaults: {
value: 'Value',
name: 'Name'
}
});
var myModel = new MyModel();
console.log(myModel.omit('value'));
Object { name="Name"}
##RESTful リクエスト
Model には、その Model を操作するための RESTful Web API を実行するメソッドが定義されている。
###サーバーから Model の情報を取得する
####レスポンスをそのまま Model のプロパティとして設定する
var MyModel = Backbone.Model.extend({
urlRoot: '/my-model'
});
var myModel = new MyModel({id: 123});
myModel
.fetch()
.success(function() {
console.log(myModel.get("name"));
});
サーバーに /my-model/123
の GET リクエストがあった場合、以下の JSON 文字列を返すようにしておく。
{
"name": "Hoge"
}
Hoge
-
urlRoot
で、サーバーにリクエストするときの基準となるパスを設定する。 - インスタンスを生成するときに、コンストラクタで
id
を渡す。- この
id
というプロパティは特別なプロパティで、 REST リクエストを実行する時のパスに自動的に埋め込まれる。 - この場合
fetch()
メソッドを実行すると、/my-model/123
に GET リクエストが送られる。
- この
-
fetch()
メソッドは jqXHR オブジェクトを返す。
####レスポンスを加工してから Model のプロパティに設定する
以下のように、サーバーからのレスポンスに Model 以外の情報が入っているようなケース。
{
"error": false,
"model": {"name": "Hoge"}
}
var MyModel = Backbone.Model.extend({
urlRoot: '/my-model',
parse: function(response) {
return response.model;
}
});
var myModel = new MyModel({id: 123});
myModel
.fetch()
.success(function() {
console.log(myModel.get("name"));
});
Hoge
-
parse()
メソッドを定義することで、レスポンスを処理したうえで Model のプロパティを設定できる。 -
parse()
メソッドの戻り値が、プロパティの情報を持つオブジェクトになるようにする。
####(補足)id プロパティ
var MyModel = Backbone.Model.extend();
var myModel = new MyModel({id: 123});
console.log(myModel.id);
-
id
プロパティは扱いが特別で、get()
メソッドを使わなくてもアクセスできる。
###POST または PUT でサーバーに Model の情報を送信する
####POST リクエスト
var MyModel = Backbone.Model.extend({
urlRoot: '/my-model'
});
var myModel = new MyModel();
myModel.save({
name: 'Hoge'
});
サーバーに送信されたリクエスト
項目 | 値 |
---|---|
URL | /my-model |
Method | POST |
Body | {"name":"Hoge"} |
####PUT リクエスト
var MyModel = Backbone.Model.extend({
urlRoot: '/my-model'
});
var myModel = new MyModel({id: 123});
myModel.save({
name: 'Hoge'
});
サーバーに送信されたリクエスト
項目 | 値 |
---|---|
URL | /my-model/123 |
Method | POST |
Body | {"id":123,"name":"Hoge"} |
-
save()
メソッドを実行すると、 POST または PUT のリクエストが送信される。-
id
が設定されていない場合は POST、設定されていれば PUT のリクエストが送信される。
-
- 引数にオブジェクトを渡すと、 JSON 文字列に変換してリクエストの Body にセットされる。
###検証処理を挟む
var MyModel = Backbone.Model.extend({
urlRoot: '/my-model',
validate: function() {
console.log('validate');
}
});
var myModel = new MyModel();
myModel.save();
validate
-
validate()
メソッドが定義されている場合、save()
メソッドを実行した時にvalidate()
メソッドが実行される。 -
validate()
メソッドが検証した結果、不正であると判定した場合、サーバーリクエストは実行されない。
###DELETE リクエストを送信する
var MyModel = Backbone.Model.extend({
urlRoot: '/my-model'
});
var myModel = new MyModel({id: 123});
myModel.destroy();
-
/my-model/123
に DELETE メソッドのリクエストが送信される。
##イベントの監視
###イベントハンドラの登録とイベントの発火
var MyModel = Backbone.Model.extend();
var myModel = new MyModel();
myModel.on('myEvent', function(param) {
console.log('fierd myEvent. param = ' + param);
});
myModel.trigger('myEvent', 'Parameter');
fierd myEvent. param = Parameter
-
on(<イベント名>, <コールバック>)
メソッドでイベントハンドラの登録ができる。 -
trigger(<イベント名>)
でイベントを発火できる。
###イベントハンドラをアンバインドする
####指定したイベントに紐づく全てのイベントハンドラをアンバインド
myModel.off('myEvent');
####イベントとコールバック関数を指定してアンバインドする
var MyModel = Backbone.Model.extend();
var callback1 = function() {console.log('callback1');};
var callback2 = function() {console.log('callback2');};
var myModel = new MyModel();
myModel.on('myEvent', callback1);
myModel.on('myEvent', callback2);
myModel.off('myEvent', callback1);
myModel.trigger('myEvent');
callback2
####コールバックを指定してアンバインドする
myModel.off(null, callback);
####全てのイベントハンドラをアンバインドする
myModel.off();
###1度だけコールバックされるイベントハンドラを登録する
var MyModel = Backbone.Model.extend();
var myModel = new MyModel();
myModel.once('myEvent', function() {
console.log('my event');
});
myModel.trigger('myEvent');
myModel.trigger('myEvent');
my event
###他のモデルのイベントを監視する
####イベントハンドラをバインドする
var MyModel = Backbone.Model.extend({
callback: function() {
console.log('callback!!');
}
});
var observer = new MyModel();
var target = new MyModel();
observer.listenTo(target, 'myEvent', observer.callback);
target.trigger('myEvent');
callback!!
####イベントハンドラをアンバインドする
var observer = new MyModel();
var target = new MyModel();
observer.listenTo(target, 'myEvent', observer.callback);
observer.stopListening(target);
-
off()
の時と同じ要領で、イベント指定・コールバック指定でアンバインドができる。
####1度だけコールバックされる(ry
observer.listenToOnce(target, 'myEvent', observer.callback);
###Collection, View でもイベントを監視する
後述する Collection や View でも、同様の方法でイベントハンドラの登録ができる。
#Collection
##基本操作
###Collection を作成する
var MyCollection = Backbone.Collection.extend();
var myCollection = new MyCollection();
-
Backbone.Collection.extend()
で Collection のコンストラクタ関数を作成できる。
###コンストラクタで初期値を設定する
var MyCollection = Backbone.Collection.extend();
var myCollection = new MyCollection([
{name: 'Hoge'},
{name: 'Fuga'}
]);
myCollection.each(function(e, i) {
console.log(e instanceof Backbone.Model);
console.log(i + ' : ' + e.get('name'));
});
true
0 : Hoge
true
1 : Fuga
- Collection に登録された各要素は、 Backbone.Model のインスタンスになる。
###要素を追加する
var MyCollection = Backbone.Collection.extend();
var myCollection = new MyCollection();
myCollection.add({name: 'Hoge'});
myCollection.add([
{name: 'Fuga'},
{name: 'Piyo'}
]);
myCollection.each(function(e, i) {
console.log(i + ' : ' + e.get('name'));
});
0 : Hoge
1 : Fuga
2 : Piyo
- 単一のオブジェクト、配列、どちらでも追加できる。
-
push()
でも同じように追加できる。
####インデックスを指定して挿入する
var MyCollection = Backbone.Collection.extend();
var myCollection = new MyCollection([
{name: 'Hoge'},
{name: 'Fuga'}
]);
myCollection.add({name: 'Piyo'}, {at: 1});
myCollection.each(function(e, i) {
console.log(i + ' : ' + e.get('name'));
});
0 : Hoge
1 : Piyo
2 : Fuga
-
add()
メソッドの第二引数にオプションを渡せる。 -
{at: <挿入先のインデックス値>}
をオプションに指定することで、要素の挿入ができる。
###先頭に要素を追加する
var MyCollection = Backbone.Collection.extend();
var myCollection = new MyCollection([
{name: 'Hoge'},
{name: 'Fuga'}
]);
myCollection.unshift({name: 'Piyo'});
myCollection.each(function(e, i) {
console.log(i + ' : ' + e.get('name'));
});
0 : Piyo
1 : Hoge
2 : Fuga
###インデックスを指定して要素を取得する
var MyCollection = Backbone.Collection.extend();
var myCollection = new MyCollection([
{name: 'Hoge'},
{name: 'Fuga'}
]);
console.log(myCollection.at(1).get('name'));
Fuga
-
at()
メソッドで、インデックス指定で要素を取得できる。 -
get()
というメソッドもあるが、こちらはインデックスではなく Model の id で要素を指定する。
###先頭の要素を削除する
var MyCollection = Backbone.Collection.extend();
var myCollection = new MyCollection([
{name: 'Hoge'},
{name: 'Fuga'}
]);
myCollection.shift();
myCollection.each(function(e, i) {
console.log(i + ' : ' + e.get('name'));
});
0 : Fuga
###最後の要素を抜き取る
var MyCollection = Backbone.Collection.extend();
var myCollection = new MyCollection([
{name: 'Hoge'},
{name: 'Fuga'}
]);
var topElement = myCollection.pop();
console.log(topElement.get('name'));
myCollection.each(function(e, i) {
console.log(i + ' : ' + e.get('name'));
});
Fuga
0 : Hoge
###要素を指定して削除する
var MyCollection = Backbone.Collection.extend();
var myCollection = new MyCollection([
{name: 'Hoge'},
{name: 'Fuga'}
]);
var hoge = myCollection.at(0);
myCollection.remove(hoge);
myCollection.each(function(e, i) {
console.log(i + ' : ' + e.get('name'));
});
0 : Fuga
###全ての要素を削除する
var MyCollection = Backbone.Collection.extend();
var myCollection = new MyCollection(['hoge', 'fuga', 'piyo']);
console.log(myCollection.length);
myCollection.reset();
console.log(myCollection.length);
3
0
####全ての要素を入れ替える
var MyCollection = Backbone.Collection.extend();
var myCollection = new MyCollection(['hoge', 'fuga', 'piyo']);
console.log(myCollection.length);
myCollection.reset(['foo', 'bar']);
console.log(myCollection.length);
3
2
###要素の数(サイズ)を取得する
var MyCollection = Backbone.Collection.extend();
var myCollection = new MyCollection([
{name: 'Hoge'},
{name: 'Fuga'}
]);
console.log(myCollection.length);
2
###ソートする
var MyCollection = Backbone.Collection.extend({
comparator: 'name'
});
var myCollection = new MyCollection([
{name: 'ccc'},
{name: 'aaa'},
{name: 'bbb'}
]);
myCollection.sort();
myCollection.each(function(e, i) {
console.log(i + ' : ' + e.get('name'));
});
0 : aaa
1 : bbb
2 : ccc
-
sort()
メソッドでソートできる。 - このとき、
comparator
を定義しておく必要がある。 -
comparator
ではソートの基準となるプロパティの名前を指定する。
####ソート方法を詳細に定義する
var MyCollection = Backbone.Collection.extend({
comparator: function(left, right) {
return left.get('name') < right.get('name');
}
});
var myCollection = new MyCollection([
{name: 'ccc'},
{name: 'aaa'},
{name: 'bbb'}
]);
myCollection.sort();
myCollection.each(function(e, i) {
console.log(i + ' : ' + e.get('name'));
});
0 : ccc
1 : bbb
2 : aaa
-
comparator
に関数を指定すると、ソートの条件を詳細に定義できる。 - 関数は以下のルールで戻り値を返すように実装する。
- 第一引数 < 第二引数の場合は
-1
を返す。 - 第一引数 == 第二引数の場合は
0
を返す。 - 第一引数 > 第二引数の場合は
1
を返す。
- 第一引数 < 第二引数の場合は
###各要素から、指定したプロパティだけを抽出したリストを取得する
var MyCollection = Backbone.Collection.extend();
var myCollection = new MyCollection([
{name: 'Hoge'},
{name: 'Fuga'},
{name: 'Piyo'}
]);
var names = myCollection.pluck('name');
console.log(names);
["Hoge", "Fuga", "Piyo"]
###プロパティが指定した値の要素だけを抽出したリストを取得する
var MyCollection = Backbone.Collection.extend();
var myCollection = new MyCollection([
{name: 'Hoge', age: 12},
{name: 'Fuga', age: 14},
{name: 'Piyo', age: 12}
]);
var array = myCollection.where({age: 12});
_.each(array, function(e, i) {
console.log(i + ' : ' + e.get('name'));
});
0 : Hoge
1 : Piyo
-
filter()
でも実現できるが、条件がシンプルな場合はwhere()
を使えば簡潔に書ける。
###プロパティが指定した値の要素のうち、先頭の要素だけを取得する
var MyCollection = Backbone.Collection.extend();
var myCollection = new MyCollection([
{name: 'Hoge', age: 12},
{name: 'Fuga', age: 14},
{name: 'Piyo', age: 12}
]);
var element = myCollection.findWhere({age: 12});
console.log(element.get('name'));
Hoge
###指定した範囲の要素を取得する
var MyCollection = Backbone.Collection.extend();
var myCollection = new MyCollection([
{name: 'Hoge', age: 12},
{name: 'Fuga', age: 14},
{name: 'Piyo', age: 12}
]);
var array = myCollection.slice(1, 3);
_.each(array, function(e, i) {
console.log(i + ' : ' + e.get('name'));
});
0 : Fuga
1 : Piyo
###要素の型を指定する
var MyModel = Backbone.Model.extend({
method: function() {
console.log('My name is ' + this.get('name') + '.');
}
});
var MyCollection = Backbone.Collection.extend({
model: MyModel
});
var myCollection = new MyCollection([
{name: 'Hoge', age: 12},
{name: 'Fuga', age: 14},
{name: 'Piyo', age: 12}
]);
var hoge = myCollection.at(0);
console.log(hoge instanceof MyModel);
hoge.method();
true
My name is Hoge.
-
model
に Model のコンストラクタを指定する。 - すると、要素に登録したオブジェクトは、指定した型のインスタンスに変換される。
##Underscore.js のメソッドを使う
Model 同様、 forEach
や map
など、リストで使える Underscore.js の関数がメソッドとして提供されている。
数が多い(28個)ので、 こちら を参照のこと。
##REST リクエスト
###コレクションの情報をサーバーから取得する
var MyCollection = Backbone.Collection.extend({
url: '/my-collection'
});
var myCollection = new MyCollection();
myCollection
.fetch()
.success(function() {
myCollection.each(function(e, i) {
console.log(i + ' : ' + e.get('name'));
});
});
[
{"name": "Hoge"},
{"name": "Fuga"},
{"name": "Piyo"}
]
0 : Hoge
1 : Fuga
2 : Piyo
-
fetch()
メソッドを使えば、サーバーから情報を GET リクエストで取得し、要素として設定することができる。 - 基本的に Model の場合と同じ要領で使えるが、以下のような違いがある。
-
urlRoot
ではなく、url
を設定する。 - 最終的に、設定する値は配列になるようにする。
-
###要素を追加し、サーバーに POST リクエストを送信する
var MyCollection = Backbone.Collection.extend({
url: '/my-collection'
});
var myCollection = new MyCollection([
{name: 'Hoge'},
{name: 'Fuga'}
]);
myCollection
.create({name: 'Piyo'}, {
success: function() {
myCollection.each(function(e, i) {
console.log(i + ' : ' + e.get('name'));
});
}
});
サーバーに送信されたリクエスト
項目 | 値 |
---|---|
URL | /my-collection |
Method | POST |
Body | {"name":"Piyo"} |
0 : Hoge
1 : Fuga
2 : Piyo
-
create()
は新しく追加された要素を return する。
#View
View といっても、これ自体がなにか DOM を操作する仕組みを提供してくれるわけではない。
DOM 操作は普通に jQuery とかを使う。
DOM 操作をするうえで便利になるプロパティとか(el
, $el
など)が Backbone.View
によって提供される。
##View を作成する
var MyView = Backbone.View.extend();
var myView = new MyView();
-
Backbone.View.extend()
で View のコンストラクタ関数を取得できる。
##コンストラクタを定義する
var MyView = Backbone.View.extend({
constructor: function() {
console.log('constructor');
}
});
var myView = new MyView();
constructor
- Model と同じで、
constructor
またはinitialize
という名前のインスタンスメソッドを定義すれば、インスタンス生成時に実行される。
##DOM オブジェクトを取得する
var MyView = Backbone.View.extend();
var myView = new MyView();
console.log(myView.el.toString());
[object HTMLDivElement]
-
el
プロパティに DOM オブジェクトが設定されている。 - デフォルトは、
div
タグのオブジェクトになる。 - この DOM オブジェクトは、あくまでメモリ上で生成されているもので、まだ HTML 上には表示されていない。
###タグを指定する
var MyView = Backbone.View.extend({
tagName: 'span'
});
var myView = new MyView();
console.log(myView.el.toString());
[object HTMLSpanElement]
-
tagName
プロパティを設定することで、タグを指定できる。
###id 属性を設定する
var MyView = Backbone.View.extend({
id: 'my-id'
});
var myView = new MyView();
console.log(myView.el.id);
my-id
###class 属性を指定する
var MyView = Backbone.View.extend({
className: 'my-class'
});
var myView = new MyView();
console.log(myView.el.className);
my-class
##jQuery オブジェクトを取得する
$(function() {
var MyView = Backbone.View.extend();
var myView = new MyView();
myView.$el
.text('jQuery object')
.appendTo('body');
});
-
$el
プロパティに、 DOM オブジェクトをラップした jQuery オブジェクトが設定されている。
##既存の DOM を紐付ける
<!DOCTYPE html>
<html>
<head>
<script src="underscore-min.js"></script>
<script src="jquery-2.1.1.min.js"></script>
<script src="backbone-min.js"></script>
<script src="script.js"></script>
</head>
<body>
<div id="hoge">
<ul>
<li class="foo">#hoge ul .foo</li>
<li class="bar">#hoge ul .bar</li>
</ul>
<ol>
<li class="foo">#hoge ol .foo</li>
<li class="bar">#hoge ol .bar</li>
</ol>
</div>
<div id="fuga">
<ul>
<li class="foo">#fuga ul .foo</li>
<li class="bar">#fuga ul .bar</li>
</ul>
</div>
</body>
</html>
$(function() {
var MyView = Backbone.View.extend({
el: '#hoge ul .foo'
});
var myView = new MyView();
myView.$el.css('color', 'red');
});
-
el
プロパティに CSS セレクターを設定することで、既存の DOM オブジェクトを紐付けることができる。 -
el
プロパティを設定した場合、tagName
やclassName
などのプロパティの設定は無視される。
##View の DOM オブジェクトを起点にして jQuery 関数を使用する
<!DOCTYPE html>
<html>
<head>
<script src="underscore-min.js"></script>
<script src="jquery-2.1.1.min.js"></script>
<script src="backbone-min.js"></script>
<script src="script.js"></script>
</head>
<body>
<div>
<span class="foo">Hoge</span>
<span class="bar">Fuga</span>
</div>
<span class="foo">Piyo</span>
</body>
</html>
$(function() {
var MyView = Backbone.View.extend({
el: 'div'
});
var myView = new MyView();
console.log(myView.$('.foo').text());
});
Hoge
-
$()
メソッドを使うと、 View の DOM を起点にして jQuery 関数が使用できる。 - これは、
myView.$el.find()
と同じ操作になる。
##render メソッド
$(function() {
var MyView = Backbone.View.extend({
render: function() {
this.$el.html('<b>Render</b>');
return this;
}
});
var myView = new MyView();
$('body').append(myView.render().el);
});
-
render()
メソッドは、デフォルトではthis
を返すだけで何も処理をしない。 -
render()
メソッドでは、 DOM に Model の情報を書き出したり、 DOM ツリー構造の構築を行う。- デフォルトの処理に合わせて、
this
を返すようにしておくのが良い。
- デフォルトの処理に合わせて、
- 別に、このメソッドが Backbone.js の何らかの処理から呼ばれるわけではなさそう。
- つまり、前述のような初期化処理を
render()
という名前のメソッドで実装する必然性は無い。 - しかし、
render()
メソッドはデフォルトでは「何もしない」という振る舞いをするので、 Null オブジェクトパターン的な使い方ができるというアドバンテージがある。
- つまり、前述のような初期化処理を
##イベントハンドリングの定義を一箇所にまとめる
<!DOCTYPE html>
<html>
<head>
<script src="underscore-min.js"></script>
<script src="jquery-2.1.1.min.js"></script>
<script src="backbone-min.js"></script>
<script src="script.js"></script>
</head>
<body>
<div id="hoge">
<button id="fuga">fuga</button>
<button id="piyo">piyo</button>
</div>
</body>
</html>
$(function() {
var MyView = Backbone.View.extend({
el: '#hoge',
events: {
'click #fuga': 'onClickFuga',
'click #piyo': 'onClickPiyo'
},
onClickFuga: function() {
console.log('fuga');
},
onClickPiyo: function() {
console.log('piyo');
}
});
var myView = new MyView();
});
- ボタンをクリックすれば、それぞれコンソールに
fuga
,piyo
と出力される。 -
events
プロパティで、監視するイベント・要素、そしてコールバックする関数のマッピングを定義できる。- 書式は、
'<イベント> <セレクター>': '<コールバック関数名>'
。 - セレクターは、 View オブジェクトの
el
要素からの相対的な位置を指すように指定する。 - セレクターを省略した場合、監視対象は View オブジェクトの
el
が指す要素になる。
- 書式は、
#Router
SPA なページを作る時に必要になる URL の操作や、 URL 変更のイベントを制御するための仕組みを提供してくれる。
##Router を作成する
var MyRouter = Backbone.Router.extend();
var myRouter = new MyRouter();
-
Backbone.Router.extend()
でコンストラクタ関数を作成する。
##コンストラクタを定義する
var MyRouter = Backbone.Router.extend({
constructor: function() {
console.log('constructor');
}
});
var myRouter = new MyRouter();
constructor
- Model とかと同じ。
##パスが変更されたときのイベントハンドラを定義する
var MyRouter = Backbone.Router.extend({
routes: {
'top': 'onTop'
},
onTop: function() {
console.log('onTop');
}
});
var myRouter = new MyRouter();
Backbone.history.start();
location.href = '#/top';
onTop
- キーに URL、値に関数名を設定したオブジェクトを、
routes
プロパティに設定する。 - キーで指定した URL に切り替わると、関数名で指定した関数が実行される。
- Router を有効にするには、 Router インスタンスの初期化が完了した後に、
Backbone.history.start()
を実行しなければならない。
###パスパラメータを取得する
var MyRouter = Backbone.Router.extend({
routes: {
'user/:id': 'userInfoPage'
},
userInfoPage: function(id) {
console.log('id = ' + id);
}
});
var myRouter = new MyRouter();
Backbone.history.start();
location.href = '#/user/1402';
id = 1402
- URL の定義に
:
始まりの文字列を入れることで、その値を関数の引数で受け取ることができる。 - 複数定義した場合は、定義した順序で関数の引数に渡される(名前は関係ない)。
##パスを変更する
var MyRouter = Backbone.Router.extend({
routes: {
'test': 'test'
},
test: function() {
console.log('test');
}
});
var myRouter = new MyRouter();
Backbone.history.start();
myRouter.navigate('test');
- ブラウザの URL は変わるが、イベントハンドリングの関数は実行されない。
###URL 切替時にイベントを発火させる
var MyRouter = Backbone.Router.extend({
routes: {
'test': 'test'
},
test: function() {
console.log('test');
}
});
var myRouter = new MyRouter();
Backbone.history.start();
myRouter.navigate('test', {trigger: true});
test
-
navigate()
メソッドの第二引数に、設定を渡す。 - 設定で、
trigger: true
を指定すると、 URL 切替時にイベントが発火して、イベントハンドラが実行されるようになる。
###パス変更時に履歴を残さない
####デフォルトの動作
var MyRouter = Backbone.Router.extend();
var myRouter = new MyRouter();
Backbone.history.start();
myRouter.navigate('test');
- デフォルトでは、パス変更前の履歴が残る。
####履歴を残さない設定
var MyRouter = Backbone.Router.extend();
var myRouter = new MyRouter();
Backbone.history.start();
myRouter.navigate('test', {replace: true});
- 設定で、
replace: true
を指定すると、パス変更前の履歴を残さないようにできる。
##ハッシュバングを使わない
Backbone.history.start({pushState: true});
- ハッシュバングを使わないようにする場合は、
Backbone.history.start()
メソッドの引数に{pushStatu: true}
を渡す。
#標準で用意されているイベント
イベントは自分で任意のものを作ることができるが、標準で用意されているイベントもある。
##Model
###プロパティの変更を監視する
var MyModel = Backbone.Model.extend();
var myModel = new MyModel({
name: 'hoge'
});
myModel.on('change', function(model, options) {
console.log('change property');
});
myModel.set('name', 'fuga');
change property
####特定のプロパティの変更だけを監視する
var MyModel = Backbone.Model.extend();
var myModel = new MyModel({
name: 'hoge',
age: 12
});
myModel.on('change:age', function(model, value, options) {
console.log('change age property');
});
myModel.set('name', 'fuga');
myModel.set('age', 15);
change age property
-
change:<プロパティ名>
で、指定したプロパティの変更だけを監視できる。
###検証エラーのイベントを監視する
var MyModel = Backbone.Model.extend({
validate: function() {
return 'test error';
}
});
var myModel = new MyModel();
myModel.on('invalid', function(model, error, options) {
console.log('invalid. error=' + error);
});
myModel.isValid();
invalid. error=test error
##Collection
###要素の追加を監視する
var MyCollection = Backbone.Collection.extend();
var myCollection = new MyCollection();
myCollection.on('add', function(model, collection, options) {
console.log('add model');
});
myCollection.add('value');
add model
###要素の削除を監視する
var MyCollection = Backbone.Collection.extend();
var myCollection = new MyCollection('hoge');
myCollection.on('remove', function(model, collection, options) {
console.log('remove model');
});
var hoge = myCollection.at(0);
myCollection.remove(hoge);
remove model
###Collection のリセットを監視する
var MyCollection = Backbone.Collection.extend();
var myCollection = new MyCollection(['hoge', 'fuga', 'piyo']);
myCollection.on('reset', function(collection, options) {
console.log('reset collection');
});
myCollection.reset();
reset collection
###ソートを監視する
var MyCollection = Backbone.Collection.extend({
comparator: 'name'
});
var myCollection = new MyCollection([
{name: 'hoge'},
{name: 'fuga'},
{name: 'piyo'}
]);
myCollection.on('sort', function(collection, options) {
console.log('sort collection');
});
myCollection.sort();
sort collection
##RESTリクエスト関係のイベント
###Model 削除のイベント
var MyModel = Backbone.Model.extend({
urlRoot: '/my-model'
});
var myModel = new MyModel({id: '123'});
myModel.on('destroy', function(model, collection, options) {
console.log('destroy model');
});
myModel.destroy();
destroy model
###サーバーにリクエストを送信したときのイベント
###Model
var MyModel = Backbone.Model.extend({
urlRoot: '/my-model'
});
var myModel = new MyModel({id: '123'});
myModel.on('request', function(model, xhr, options) {
console.log('request');
});
myModel.fetch();
myModel.save();
myModel.destroy();
request
request
request
###Collection
var MyCollection = Backbone.Collection.extend({
url: '/my-collection'
});
var myCollection = new MyCollection();
myCollection.on('request', function(collection, xhr, options) {
console.log('request');
});
myCollection.fetch();
myCollection.create();
request
request
##サーバーリクエストが成功したときのイベント
###Model
var MyModel = Backbone.Model.extend({
urlRoot: '/my-model'
});
var myModel = new MyModel({id: '123'});
myModel.on('sync', function(model, xhr, options) {
console.log('sync');
});
myModel.fetch();
sync
###Collection
var MyCollection = Backbone.Collection.extend({
url: '/my-collection'
});
var myCollection = new MyCollection();
myCollection.on('sync', function(collection, response, options) {
console.log('sync');
});
myCollection.fetch();
sync
##サーバーリクエストが失敗したときのイベント
###Model
var MyModel = Backbone.Model.extend({
urlRoot: '/unknown-url'
});
var myModel = new MyModel({id: '123'});
myModel.on('error', function(model, response, options) {
console.log('error');
});
myModel.fetch();
error
###Collection
var MyCollection = Backbone.Collection.extend({
url: '/unknown-url'
});
var myCollection = new MyCollection();
myCollection.on('error', function(collection, response, options) {
console.log('error');
});
myCollection.fetch();
error
#参考