関連記事
- 勉強会JS編<1> オブジェクト指向言語としてのJavaScriptを理解
- 勉強会JS編<2> クライアントサイドMVCフレームワーク
- 勉強会JS編<3> フロントエンド開発環境構築
- 勉強会JS編<4> yeoman + backbone.model + grunt
- 勉強会JS編<5> yeoman + backbone.collection + backbone.localStorage
- 勉強会JS編<6> yeoman + backbone.view
- 勉強会JS編<7> yeoman + backbone.router
- 勉強会JS編<8> yeoman + backbone.js 実践 - その1
- 勉強会JS編<9> yeoman + backbone.js 実践 - その2
Backbone.Collectionとは
- 複数のBackbone.Modelを保持し、管理するコレクション
- extend()を使ってBackbone.Collectionの機能を継承するオブジェクトを作成して使う。
実習
オブジェクトの定義
- yeomanでcontactというcollectionを生成する。
[devnote@hooni:~/documents/study/js/sample] % yo backbone:collection contact
create app/scripts/collections/contact.js
create test/collections/contact.spec.js
- コレクションの定義
// app/scripts/collections/contact.js
/*global Sample, Backbone*/
Sample.Collections = Sample.Collections || {};
(function () {
'use strict';
Sample.Collections.Contact = Backbone.Collection.extend({
// modelプロパティにどのモデルを管理するかを宣言する。
// この宣言によって、コレクションが保持するモデルはContactのインスタンスとなる。
model: Sample.Models.Contact,
// initialize()メソッドを定義できる点はBackbone.Modelと同様
initialize: function() {
console.log('ContactCollectionが初期化されました。');
}
});
})();
モデルの追加
- add()
// app/scripts/main.js
collection_ex01: function(contact) {
var contactCollection = new Sample.Collections.Contact();
contactCollection.add(contact);
var ichiro = new Sample.Models.Contact({
firstname: '一郎',
lastname: '鈴木',
email: 'suzuki@example.com'
});
contactCollection.add(ichiro);
console.log(JSON.stringify(contactCollection, null, 2));
console.log(contactCollection.length);
},
...snip...
$(document).ready(function () {
'use strict';
var c = Sample.init();
Sample.collection_ex01(c);
});
- 同じモデルを追加する場合
// app/scripts/main.js
// すでに追加されているモデルが渡された場合は、何も行わない。
collection_ex02: function(contact) {
'use strict';
var contactCollection = new Sample.Collections.Contact();
contactCollection.add(contact);
contactCollection.add(contact);
console.log(JSON.stringify(contactCollection, null, 2));
},
...snip...
$(document).ready(function () {
'use strict';
var c = Sample.init();
Sample.collection_ex02(c);
});
- モデルのインスタンスではなく、オブジェクトを渡す場合
// app/scripts/main.js
// オブジェクトを渡しても結果は同様
collection_ex03: function(contact) {
'use strict';
var contactCollection = new Sample.Collections.Contact();
contactCollection.add(contact);
contactCollection.add({
firstname: '一郎',
lastname: '鈴木',
email: 'suzuki@example.com'
});
console.log(JSON.stringify(contactCollection, null, 2));
},
...snip...
$(document).ready(function () {
'use strict';
var c = Sample.init();
Sample.collection_ex03(c);
});
- モデルを一括追加する場合
// app/scripts/main.js
// オブジェクトの配列を渡すことで一度に複数のモデルを生成する。
collection_ex04: function(contact) {
'use strict';
var contactCollection = new Sample.Collections.Contact();
contactCollection.add([
{
firstname: '太郎',
lastname: '山田',
email: 'yamada@example.com'
}, {
firstname: '一郎',
lastname: '鈴木',
email: 'suzuki@example.com'
}
]);
console.log(JSON.stringify(contactCollection, null, 2));
},
...snip...
$(document).ready(function () {
'use strict';
var c = Sample.init();
Sample.collection_ex04(c);
});
- コレクションを初期化する際にモデルを渡す場合
// app/scripts/main.js
collection_ex05: function(contact) {
'use strict';
var ichiro = new Sample.Models.Contact({
firstname: '一郎',
lastname: '鈴木',
email: 'suzuki@example.com'
});
var contactCollection = new Sample.Collections.Contact([contact, ichiro]);
console.log(JSON.stringify(contactCollection, null, 2));
return contactCollection;
},
...snip...
$(document).ready(function () {
'use strict';
var c = Sample.init();
Sample.collection_ex05(c);
});
モデルの削除
- remove()
// app/scripts/main.js
collection_ex06: function(contact, contactCollection) {
'use strict';
contactCollection.remove(contact);
console.log(JSON.stringify(contactCollection, null, 2));
},
...snip...
$(document).ready(function () {
'use strict';
var c = Sample.init();
var cc = Sample.collection_ex05(c);
Sample.collection_ex06(c, cc);
});
モデルのリセット
- reset()
- 保持しているモデルをすべて新しいものに入れ替える。
// app/scripts/main.js
collection_ex07: function(contact, contactCollection) {
'use strict';
var tanaka = new Sample.Models.Contact({
firstname: '田中',
lastname: '将大',
email: 'tanaka@example.com'
});
contactCollection.reset([tanaka]);
console.log(JSON.stringify(contactCollection, null, 2));
},
...snip...
$(document).ready(function () {
'use strict';
var c = Sample.init();
var cc = Sample.collection_ex05(c);
Sample.collection_ex07(c, cc);
});
イベント
- add
// app/scripts/main.js
collection_ex08: function(contact, contactCollection) {
'use strict';
contactCollection.on('add', function(contact) {
console.log('モデルが追加されました。', contact.get('firstname'));
});
var tanaka = new Sample.Models.Contact({
firstname: '田中',
lastname: '将大',
email: 'tanaka@example.com'
});
contactCollection.add(tanaka);
console.log(JSON.stringify(contactCollection, null, 2));
},
...snip...
$(document).ready(function () {
'use strict';
var c = Sample.init();
var cc = Sample.collection_ex05(c);
Sample.collection_ex08(c, cc);
});
Underscore.jsの機能
- JavaScriptを拡張するユーティリティライブラリ
- オブジェクトを操作するための便利な機能を提供する。
- 本来は_.each(someArray, function() {...})ように使用するが、コレクションに対して直接呼び出すこともできる。
ContactCollection.each(function(contact) {
// ...
})
- 使用例:filter()
- 条件に合致するモデルを配列にいて返す。
// app/scripts/main.js
collection_ex09: function() {
'use strict';
var ichiro = new Sample.Models.Contact({
firstname: '一郎',
lastname: '鈴木',
age: 42,
email: 'suzuki@example.com'
});
var tanaka = new Sample.Models.Contact({
firstname: '田中',
lastname: '将大',
age: 27,
email: 'tanaka@example.com'
});
var aoki = new Sample.Models.Contact({
firstname: '青木',
lastname: '宣親',
age: 34,
email: 'aoki@example.com'
});
var contactCollection = new Sample.Collections.Contact([ichiro, tanaka, aoki]);
var filtered = contactCollection.filter(function(contact) {
// Contactモデルがage(年齢)属性を持っていたとして、それ年齢が30以上のモデルだけを抽出した配列を返す。
return contact.get('age') >= 30;
});
console.log(JSON.stringify(filtered, null, 2));
}
...snip...
$(document).ready(function () {
'use strict';
Sample.collection_ex09();
});
データの永続化
-
データの取得
- fetch()
- Backbone.ModelとBackbone.Collectionのインスタンスから使用できる。
- fetch()は内部で$.ajaxメソッドを使うので、successやerrorオプションにコールバック関数を渡すことができる。
- 戻り値はjQueryのPromiseオブジェクト
- fetch()完了後、コレクションはsyncイベントを発生させる。
- fetch()
-
データの保存
- save()
- Backbone.Modelのインスタンスから使える。
- create()
- Backbone.Collectionのインスタンスから使える。
- モデルの生成、コレクションへの追加、サーバへの送信をまとめて行う。
- save()
-
データ保存の仕組み
- モデルがid属性を持っていない場合、コレクションに設定されているurlプロパティに対してPOST形式のHTTPリクエストが行われる。
- モデルがid属性を持っている場合、コレクションのurlプロパティとモデルのid属性値を連結したパスにPUTリクエストが行われる。
-
データの削除
- destroy()
- Backbone.Modelのインスタンスから使える。
- 該当モデルはコレクションやサーバから削除される。
- 該当モデルと対応するURLに対して実際にDELETEのHTTPリクエストが送信される。
- 該当モデルを保持していたコレクションがremoveとdestroyイベントを発生させる。
- destroy()
-
backbone.localStorage
- RESTインターフェイスを通じてサーバ側にデータを保持することではなくBackbone.Syncを上書きしデータストアとしてHTML5ローカルストレージを使う。
- 設置(localStorageではなくbackbone.localStorageである)
[devnote@hooni:~/Documents/study/js/sample] % bower install backbone.localStorage --save
bower backbone.localStorage#* cached git://github.com/jeromegn/Backbone.localStorage.git#1.1.16
bower backbone.localStorage#* validate 1.1.16 against git://github.com/jeromegn/Backbone.localStorage.git#*
bower backbone.localStorage#~1.1.16 install backbone.localStorage#1.1.16
backbone.localStorage#1.1.16 app/bower_components/backbone.localStorage
└── backbone#1.1.2
[devnote@hooni:~/Documents/study/js/sample] % bower list
bower check-new Checking for new versions of the project dependencies...
sample#0.0.0 /Users/devnote/Documents/study/js/sample
├─┬ backbone#1.1.2 (latest is 1.2.3)
│ └── underscore#1.8.3
├─┬ backbone.localStorage#1.1.16 extraneous
│ └── backbone#1.1.2 (1.2.3 available)
├─┬ bootstrap-sass-official#3.3.6
│ └── jquery#2.1.4 (3.0.0-beta1 available)
├── chai#3.4.2
├── jquery#2.1.4 (latest is 3.0.0-beta1)
├── lodash#2.4.2 (latest is 4.0.1)
└── mocha#2.3.4
- bower.jsonを確認する。dependenciesにbackbone.localStorageが追加されている。
{
"name": "sample",
"version": "0.0.0",
"dependencies": {
"bootstrap-sass-official": "~3.3.1",
"jquery": "~2.1.0",
"backbone": "~1.1.0",
"lodash": "~2.4.1",
"backbone.localStorage": "~1.1.16"
},
"devDependencies": {
"chai": "~3.4.2",
"mocha": "~2.3.4"
}
}
- app/index.htmlにてbackbone.localStorageを読み込む。
<!-- build:js scripts/vendor.js -->
<script src="bower_components/jquery/dist/jquery.js"></script>
<script src="bower_components/lodash/dist/lodash.compat.js"></script>
<script src="bower_components/backbone/backbone.js"></script>
<script src="bower_components/backbone.localStorage/backbone.localStorage.js"></script>
<!-- endbuild -->
- app/scripts/collections/contact.jsにてlocalStorageのオブジェクトを生成する。
// app/scripts/collections/contact.js
...snip...
model: Sample.Models.Contact,
// localStorage
localStorage: new Backbone.LocalStorage("Sample.Collections.Contact"),
...snip...
- Backbone.Collectionのcreate()
// app/scripts/main.js
collection_ex10: function() {
'use strict';
var ichiro = new Sample.Models.Contact({
firstname: '一郎',
lastname: '鈴木',
age: 42,
email: 'suzuki@example.com'
});
var tanaka = new Sample.Models.Contact({
firstname: '田中',
lastname: '将大',
age: 27,
email: 'tanaka@example.com'
});
var aoki = new Sample.Models.Contact({
firstname: '青木',
lastname: '宣親',
age: 34,
email: 'aoki@example.com'
});
var contactCollection = new Sample.Collections.Contact();
contactCollection.create(ichiro);
contactCollection.create(tanaka);
contactCollection.create(aoki);
},
...snip...
$(document).ready(function () {
'use strict';
var c = Sample.init();
Sample.collection_ex10();
});
- Local Storageに保持されているデータは、developer toolsにて Resources → Local Storage → http://localhost:9000 順でクリックすることで確認できる。
- grunt serveが動作されている状態でLocal Storageを確認すると、データが重複で保持されている。
- Local Storage中のデータを全部削除しページをリロードしたら、予想通りデータが保持されていた。
Sample.Collections.Contact 0c375b69-007a-a992-c8dd-eb9c1c4aa49e,f7aca131-ed31-7d66-0715-eb86d9865c5f,e6aab275-ebbb-9d72-13d6-3545c71bfe41
Sample.Collections.Contact-0c375b69-007a-a992-c8dd-eb9c1c4aa49e {"firstname":"一郎","lastname":"鈴木","age":42,"email":"suzuki@example.com","id":"0c375b69-007a-a992-c8dd-eb9c1c4aa49e"}
Sample.Collections.Contact-e6aab275-ebbb-9d72-13d6-3545c71bfe41 {"firstname":"青木","lastname":"宣親","age":34,"email":"aoki@example.com","id":"e6aab275-ebbb-9d72-13d6-3545c71bfe41"}
Sample.Collections.Contact-f7aca131-ed31-7d66-0715-eb86d9865c5f {"firstname":"田中","lastname":"将大","age":27,"email":"tanaka@example.com","id":"f7aca131-ed31-7d66-0715-eb86d9865c5f"}
- Backbone.Collectionのfetch()
// app/scripts/main.js
collection_ex11: function() {
var contactCollection = new Sample.Collections.Contact();
contactCollection.localStorage = new Backbone.LocalStorage("Sample.Collections.Contact");
contactCollection.fetch();
// console.log(contactCollection.pluck('lastname'));
contactCollection.each(function(contact) {
console.log(JSON.stringify(contact, null, 2));
});
},
...snip...
$(document).ready(function () {
'use strict';
var c = Sample.init();
Sample.collection_ex10();
Sample.collection_ex11();
});
- developer tools → Consoleにて確認する。
Hello from Backbone!
contact.js:19 ContactCollectionが初期化されました。
contact.js:19 ContactCollectionが初期化されました。
main.js:285 {
"firstname": "一郎",
"lastname": "鈴木",
"age": 42,
"email": "suzuki@example.com",
"id": "07e8e44a-55f8-ff5e-860a-9a8d1b763b39"
}
main.js:285 {
"firstname": "田中",
"lastname": "将大",
"age": 27,
"email": "tanaka@example.com",
"id": "100c3d73-ddd4-59ff-a299-cc800bbb649d"
}
main.js:285 {
"firstname": "青木",
"lastname": "宣親",
"age": 34,
"email": "aoki@example.com",
"id": "2cb06f4e-33cf-fb91-cc8e-fe390ac47e29"
}
参考書籍
- JavaScript徹底攻略
- JavaScriptエンジニア養成読本
- 入門Backbone.js