夜です。今回は何を思ったのか、backbone.jsの公式ページを眺めるという行為に及んでみたいと思います。
ちょっと見てみると、backbone.jsのルーティングがなんか便利そうじゃないですか。pushState触らなくていいとか!
ajax使うにはもうbackboneは手放せない存在なんじゃないでしょうか。githubは違うプラグイン使っているみたいですが…
公式ページ。backbone.jsの配布ページとマニュアルページがひとつに繋がっているタイプ。Ctrl+Fで検索しやすいのでなかなかいいかも。
Introduction
Google翻訳を使ってIntroductionを読んでみます。要約すると(確実に翻訳ミスがあります)
- jQueryをDOMを直接操作してHTMLを動的に動かす開発をしてるんでしょうけど、古いよ
- フロントエンドとサーバー間でデータの受け渡しに四苦八苦してる
- Backbone.jsを使うとデータの受け渡し楽よ
- Backbone.jsを使うとデータに変化が合った場合changeイベントが走って画面が動的に書き換わるから楽よ
- Backbone.jsを使うと手作業でHTML更新しなくてすむよ
- Backbone.jsがどういうものなのか下にたくさんサンプルスクリプト用意したから見てね
- 再生ボタン押すとサンプルスクリプトを直接実行できるよ
という感じな気がする。多分。
Upgrading to 1.0
1.0の変更点などが書いてある。あまり関係なさそうなので省略。
Backbone.Events
イベントは、任意のオブジェクトにイベントドリブンなメソッドを提供したりできるようです。
var object = {};
_.extend(object, Backbone.Events);Code language: JavaScript (javascript)
とするだけで、変数objectは object.on と object.trigger というメソッドを持つようになりました。onはイベントの登録、triggerはイベントの実行です。
var object = {};
_.extend(object, Backbone.Events);
object.on("alert", function(msg) {
alert("Triggered " + msg);
});
object.trigger("alert", "an event");Code language: JavaScript (javascript)
なるほど便利、 ちなみに _.extend は underscore.jsの機能で、オブジェクトに異なるオブジェクトのメソッドをもたせることができる、いわゆるサブクラスっぽいことができるメソッド。triggerで引数をわたすこともできるようです。
また、
var dispatcher = _.clone(Backbone.Events);Code language: PHP (php)
でディスパッチャの切り分けができます。
object.on(event, callback, [context])Alias: bind
オブジェクトに登録したイベントが発生するたびにコールバック関数が呼び出されます。
オブジェクトに登録したイベントが多すぎるときに分類するときは”hoge:[attribute]”と書くと良いようです。
スペース区切りすると、複数のイベントを登録させることができます。
book.on("change:title change:author", ...);Code language: CSS (css)
第三パラメータに値またはオブジェクトを渡すと、それがコールバック関数内で、thisになります。
model.on('change', this.render, this);
model.on('change', this.render, {hoge: 1});
Code language: JavaScript (javascript)
all という名前のイベントを登録すると、オブジェクトから様々なイベントが実行された後に一緒にallイベントのコールバック関数も実行されるようになります。
object.on("all", function(eventName) {
console.log(eventName);
});
Code language: JavaScript (javascript)
このような書き方(イベントマップ)でもイベントを登録することができます。これだと一括でイベントが登録できるので楽。
book.on({
"change:title": titleView.update,
"change:author": authorPane.update,
"destroy": bookView.remove
});Code language: JavaScript (javascript)
object.off([event], [callback], [context]) Alias: unbind
オブジェクトから以前登録されたイベントのコールバック関数を削除するメソッドです。
コンテキストが指定されていない場合は、コールバックのすべてのイベントが削除される。
コールバックが指定されていない場合は、イベントのすべてのコールバックが削除。
イベントが指定されていない場合は、すべてのイベントのコールバックは削除。
event→callback→contextと削除される条件と範囲が変わるようです。ということは、同じイベント名でもコールバック関数が違えば、上書きされず2つとも実行される仕様のようですね。下記スクリプトでテストしてみることにします。
var o = {};
_.extend(o, Backbone.Events);
o.on("hoge", function() {
console.log("hoge1");
});
o.on("hoge", function() {
console.log("hoge2");
});
o.trigger("hoge");
Code language: PHP (php)
2つ出力されたので、2つのコールバック関数が実行されることが確認出ました。イベント名が同じ場合、オーバーライド(上書き)されるのではなく、順々に実行されるようです。
offメソッドの使い方は下記の通り。
object.off("change", onChange);
object.off("change");
object.off(null, onChange);
object.off(null, null, context);
object.off();Code language: JavaScript (javascript)
onメソッドの使い方サンプルではよくわかりませんでしたが、offメソッドのサンプルを見ることで、backboneのイベントがどこまで柔軟なことができるか目に見えてわかりますね。。null = 全て の範囲はおそらく、backbone.Eventsを使って登録したイベントの範囲なのでしょうから、
var dispatcher = _.clone(Backbone.Events);Code language: PHP (php)
によってディスパッチャをわけることで、この全ての範囲をわけることも可能だということにメリットも感じられます。
object.trigger(event, [*args])
eventを実行します。”event event”の書き方であればそれぞれのイベントを実行します。
argsでは,区切りで引数を付けることができます。
ただそれだけ!とてもシンプル!!
object.once(event, callback, [context])
一度実行されたら削除されるイベントです。
var o = {};
_.extend(o, Backbone.Events);
o.on("hoge", function() {
console.log("hoge1");
});
o.once("hoge", function() {
console.log("hoge2");
});
o.trigger("hoge");
o.trigger("hoge");Code language: JavaScript (javascript)
イベントといってもコールバック関数が削除されるので、hoge1コールバック関数は消されずに残っています。hoge2だけが実行されません。なるほど便利。
object.listenTo(other, event, callback)
多分、後でlistenToについて説明した項があるんでしょうけど、やっぱり気になるのでここで説明すると、otherは var model = new Backbone.Model(); で作ったモデルに対してeventが発生すると、callbackを実行してくれるというもの。
var o = {};
_.extend(o, Backbone.Events);
var model = new Backbone.Model();
o.listenTo(model, 'change', function () {
console.log("モデルデータに変化がありました", this);
});
model.set("hoge", "ほげほげ");
Code language: JavaScript (javascript)
サンプルだと、モデルに変化があると実行してくれます。 this の中身は o になっているので、モデルに対して o のメソッドが使えるので、 o のメソッドを使ってモデルに対していろんなことができます。なるほど、便利。
眠いけど、どんどんいきます。
object.stopListening([other], [event], [callback])
listenToの逆、イベントの監視をストップします。
view.stopListening();
view.stopListening(model);Code language: JavaScript (javascript)
object.listenToOnce(other, event, callback)
ちょうどlistenToを同じような振る舞いをしますが、一度監視でコールバック関数が実行されると、監視を終了します。
var o = {};
_.extend(o, Backbone.Events);
var model = new Backbone.Model();
o.listenToOnce(model, 'change', function () {
console.log("モデルデータに変化がありました", this);
});
model.set("hoge", "ほげほげ");
model.set("hoge", "ほげほげ");
Code language: JavaScript (javascript)
ずいぶんとやる気のないメソッドですね。
Catalog of Events
モデルやビューやコレクションに対して独自にイベントを定義し利用することは自由だけれど、そのほかにBackbone.jsが独自に追加しているイベントもあるようで、それが下記の通り。
add
モデルがコレクションに追加されたとき呼ばれます。
remove
モデルがコレクションから削除されたとき呼ばれます。
reset
コレクションが新しく作りなおされたときに呼び出されます。(あいまい)
sort
コレクションが再ソートされたとき呼ばれます。
change
モデルの属性が変更されたとき呼ばれます。(よく使われます)
change:[attribute]
モデルの持っている特定の値が変更されたときのみ呼ばれます
destroy
モデルが削除されたとき呼ばれます。
request
モデルまたはコレクションがサーバーにリクエストを送った時に呼ばれます。
sync
モデルまたはコレクションが正常にサーバーと同期されているときに呼ばれます。
error
モデルの内容をサーバーに送り保存しようとしたときに、サーバーエラーが発生した場合呼ばれます。
invalid
モデルの検証がクライアント上で失敗したときに呼ばれます。
route:[name]
指定されたルーティングが一致しているとき実行します
route
任意のルーティングが一致したとき、または履歴によって一致したときに呼び出されます。
all
このイベントは、第一パラメータにイベント名を渡し、あらゆるイベントに対しても呼び出されます。Code language: CSS (css)
わかるのもありけど、よくわからないのもありますね。ルーティング…?
また、これらイベントは model.set(), collection.add 等のメソッドによって呼ばれるので、 model[“hoge”] = 1 なんてしても呼ばれることはないようです。また、model.set等でモデルにデータを追加した場合に、イベントが呼ばれるのが嫌な場合は、
var o = {silent: true};
_.extend(o, Backbone.Events);
var model = new Backbone.Model({silent: true});
o.listenToOnce(model, 'change', function () {
console.log("モデルデータに変化がありました", this);
});
model.set("hoge", "ほげほげ", {silent: true});
Code language: JavaScript (javascript)
というよう第三パラメータ、 silent: true を渡すことで、イベントが発生しないようです。
Backbone.Model
ふぅ… いよいよModelへはいります。
Modelというのはデータ構造を表します。というか、データそのものです。身近なものだと、アドレス帳とか、日記とかソシャゲのガチャで集めたカードなどといったデータをまとめてモデルと言います。
Backbone.jsにおけるモデルは、JavaScriptの心臓部です。Backbone.jsはモデルに対して変換や、検証や、プロパティの追加削除機能等 様々な機能を提供します。
以下のサンプルスクリプトは公式にあげられていたものをそのままコピーしたものに日本語コメントを付与したものです。サイドバーの背景色を変更するだけの簡単なスクリプトになっています。公式ページでは再生ボタンを押すことでスクリプトを実行することができます。一度実行すると、ChromeであればWeb Developper Toolsによってモデルの書き換えを行い自由に色を変更することができるので、モデルを変更することでコールバックを実行するといった一連のフローを理解することができます。
var Sidebar = Backbone.Model.extend({
promptColor: function() {
var cssColor = prompt("Please enter a CSS color:");
this.set({color: cssColor});
}
});
window.sidebar = new Sidebar;
sidebar.on('change:color', function(model, color) {
$('#sidebar').css({background: color});
});
sidebar.set({color: 'white'});
sidebar.promptColor();Code language: JavaScript (javascript)
ソースコードの動きが読めたでしょうか、通常のコーディングでは、ボタンを押したらここの背景を変えて…みたいな処理を書いていたとおもいますが、このソースコードでは、sidebarモデルのcolorプロパティの値をwhiteに変えただけで、サイドバーの背景色が変わっています。データだけ見ることによって、ロジックまで来にしなくて済むのです。なるほど、便利。
Backbone.Model.extend(properties, [classProperties])
extendによって、Backbone.Modelを拡張し、独自のモデルクラスを生成することができます。
このモデルクラスを利用してモデルを作ると、そのモデルはpropertiesのプロパティを持つようになります。
var Note = Backbone.Model.extend({
initialize: function() {},
author: function() {},
coordinates: function() {},
allowedToEdit: function(account) {
return true;
}
});
var PrivateNote = Note.extend({
allowedToEdit: function(account) {
return account.owns(this);
}
});Code language: JavaScript (javascript)
また、定義済みのメソッドをオーバーライドしたい場合、簡単にオーバーライドできるようにな仕組みは存在ず、めんどくさいけども下記のようなやりかたで実現可能です。
var Hoge = Backbone.Model.extend({
set: function(attributes, options) {
Backbone.Model.prototype.set.apply(this, arguments);
console.log("値をセットしました");
}
});
var a = new Hoge();
a.set("hoge", "1");
console.log(a.get("hoge"));Code language: JavaScript (javascript)
constructor / initializenew Model([attributes], [options])
モデルを生成するときに、デフォルトの値を最初から定義したり、コンストラクタ(モデルを生成するタイミングで呼ばれるメソッド)を定義したりすることができます。
モデルを作成するタイミングでデフォルトの値を最初から定義する場合は、
new Book({
title: "One Thousand and One Nights",
author: "Scheherazade"
});Code language: JavaScript (javascript)
とします。
モデルを生成するタイミングでメソッドを呼び出したい場合は
var Library = Backbone.Model.extend({
constructor: function() {
this.books = new Books();
Backbone.Model.apply(this, arguments);
},
parse: function(data, options) {
this.books.reset(data.books);
return data.library;
}
});Code language: JavaScript (javascript)
このようにします。
model.get(attribute)
モデルから指定されたattributeに定義されてある値を取得します。
model.set(attributes, [options])
モデルに値をセットします。モデルに値をセットすると、changeイベントが発生します。
change:[attribute] というイベントが登録されていた場合は、その[attribute]が変更された場合のみそのイベントに関連付けられたコールバック関数が実行します。
var a = new Backbone.Model();
a.on("change", function () {
console.log("変更されましたA");
});
a.on("change:hoge", function () {
console.log("変更されましたB");
});
a.on("change:hoge2", function () {
console.log("変更されましたC");
});
a.set("hoge", "1");
Code language: JavaScript (javascript)
モデルはオブジェクトのように定義することもできます。
note.set({title: "March 20", content: "In his eyes she eclipses..."});Code language: CSS (css)
model.escape(attribute)
getメソッドと似通ってはいるけど、これはHTMLをエスケープしたものを返すので、XSS対策を行うことができます。(エスケープは、HTMLエンティティ化です)
var a = new Backbone.Model({
hoge: "<script>alert(1);</script>"
});
a.escape("hoge");
// => <script>alert(1);</script>Code language: HTML, XML (xml)
model.has(attribute)
modelがattributeを持っている場合trueを返します
var a = new Backbone.Model({
hoge: "hoge"
});
console.log(a.has("hoge"));
console.log(a.has("hogehoge"));
Code language: JavaScript (javascript)
model.unset(attribute, [options])
modelのattributeで指定されたプロパティを削除します。optionにsilent: true が指定されな限りchangeイベントが呼ばれます。
var a = new Backbone.Model({
hoge: "hoge"
});
a.unset("hoge");
console.log(a.has("hoge"));
Code language: JavaScript (javascript)
model.clear([options])
modelからid属性を含む全てのプロパティを削除します。optionsにsilent:true が指定されていない限り、changeイベントが発生します。
var a = new Backbone.Model({
hoge: "hoge"
});
a.clear();
console.log(a.has("hoge"));
Code language: JavaScript (javascript)
model.id
model.idにはユニークな値を指定することができます。特に使い方が今の段階では不明。。
model.idAttribute
model.idとして取得できる別な属性を指定することができます。これは、データベースのテーブルからデータを引っ張ってきたときにカラム名がidではない違う名前だった場合便利です。
var Meal = Backbone.Model.extend({
idAttribute: "_id"
});
var cake = new Meal({ _id: 1, name: "Cake" });
alert("Cake id: " + cake.id);Code language: JavaScript (javascript)
なるほど、データベースとのデータの整合性マッチとして model.id は使える。便利。
model.cid
自動的にすべてのモデルに割り当てられた一意の識別子です。
cidは、モデルがまだサーバーに保存されていない場合に便利です。(cidがそのままサーバーに登録するレコードidとして使える)
model.attributes
modelの内包しているオブジェクトがそのまま返ります。
var a = new Backbone.Model({
hoge1: "hoge1",
hoge2: "hoge2"
});
console.log(a.attributes)
Code language: JavaScript (javascript)
attributesによってモデルデータを直接書き換えたりすることもできます。モデルデータをコピーしたい場合は
_.clone(model.attributes);Code language: CSS (css)
を使用します。
ただ、モデルデータを直接書き換える場合、プロパティ名にキーを含ませることが可能になってしまうので、それをやってしまうと、”イベントをスペースで区切る”
model.changed
最後に変更された属性がオブジェクト(ハッシュ)で返ります。変更差分のみを保存させるロジックを書くのに便利です。
var a = new Backbone.Model({
hoge1: "hoge1",
hoge2: "hoge2"
});
a.set("hoge1", "new");
console.log(a.changed);
Code language: JavaScript (javascript)
model.defaults or model.defaults()
デフォルト値の取得および設定ができます。
var Meal = Backbone.Model.extend({
defaults: {
"appetizer": "caesar salad",
"entree": "ravioli",
"dessert": "cheesecake"
}
});
Meal.prototype.defaults["hoge"] = "hoge";
var a = new Meal();
console.log(a.defaults);
Code language: JavaScript (javascript)
デフォルト値は、モデルクラスの参照によって渡されるので、書き換えには注意が必要です。
model.toJSON()
モデルをJSON文字列に変換するためのオブジェクトを返します。このメソッドは、一見JSON文字列を返してくれるように見えますが、JSON.stringifyによって変換するためのオブジェクトが用意されるだけのものです。また、JSON.stringifyを使用する場合、toJSONが暗黙的に呼び出されるようです。(省略できます)
var a = new Backbone.Model({
hoge1: "hoge1",
hoge2: "hoge2"
});
console.log(a.toJSON());
console.log(JSON.stringify(a));
Code language: JavaScript (javascript)
model.sync(method, collection, [options])
サーバーへモデルの状態を保持する Backbone.syncを使用するためのオプションです。
model.fetch([options])
Backbone.syncを利用することで、モデルの状態を再設定します。
現在のモデルデータをサーバーから取得したモデルデータと比較して、差異が合った場合やローカル側のモデルデータが空になっている場合はchangeイベントが発生します。
var BookClass = Backbone.Model.extend({
url: "/ajax/hogehoge"
});
var book = new BookClass({
title: "The Rough Riders",
author: "Theodore Roosevelt"
});
book.fetch();
Backbone.sync = function(method, model) {
console.log(method + ": " + JSON.stringify(model));
};
var BookClass = Backbone.Model.extend({
url: "/ajax/hogehoge"
});
var book = new BookClass({
title: "The Rough Riders",
author: "Theodore Roosevelt"
});
book.fetch();Code language: JavaScript (javascript)
model.save([attributes], [options])
Backbone.syncによってモデルデータを保存します。検証に成功した場合、jqueryXHRを返します。
変更したいプロパティのみを記述し、記述されないプロパティはサーバー上から変更されません。
save時には、modelのvalidateメソッドによってデータの検証が行われるので、検証に失敗した場合は保存されません。
モデルがすでにサーバー上にある場合、HTTPメソッドはPUTとなり、ない場合は、POSTとなります。
saveが実行されると、 モデルイベントが、 change、request、syncの順番で発生します。
基本的に、saveは非同期で行われますが、サーバーの処理を待ちたい場合は、optionsに wait: true を指定します。
Backbone.sync = function(method, model) {
console.log(method + ": " + JSON.stringify(model));
model.id = 1;
};
var book = new Backbone.Model({
title: "The Rough Riders",
author: "Theodore Roosevelt"
});
book.save();
book.save({author: "Teddy"});
console.log(book.attributes);
Code language: JavaScript (javascript)
検証に失敗した場合や、通信時にエラーがあった場合は error を指定するとエラー通知を行うことができます。
book.save("author", "F.D.R.", {error: function(){ ... }});Code language: CSS (css)
model.destroy([options])
Backbone.syncによって、HTTPメソッドのDELETEによってモデルをサーバー上のデータベーステーブルから削除してもらうよう命令することができます。
Backbone.sync = function(method, model) {
console.log(method + ": " + JSON.stringify(model));
};
var book = new Backbone.Model({
id: 1,
title: "The Rough Riders",
author: "Theodore Roosevelt"
});
book.destroy({success: function(model, response) {
console.log("--");
}});
Code language: JavaScript (javascript)
モデルにid属性がない場合は、destroyは失敗しfalseが返ります。
Underscore Methods (6)
Underscoreの基本的なメソッドをモデルに対して使用することができます。_を使わなくても、モデルのメソッドとしてデリゲート(委任)されているのでそのままモデルに対して使用できます。
var a = new Backbone.Model({
hoge1: "hoge1",
hoge2: "hoge2",
hoge3: "hoge3"
});
console.log(a.pick("hoge1", "hoge2"));
console.log(a.omit("hoge1"));
console.log(a.keys());
console.log(a.values());
console.log(a.pairs());
console.log(a.invert());
Code language: JavaScript (javascript)
model.validate(attributes, options)
モデルの検証を定義するためのメソッドです。検証ロジックはデフォルトでは未定義(特に何もしない)担っています。
モデルデータによってJavaScriptの任意のコードが実行できるようなものやバックエンドに何らかの影響を及ぼすようなものに対してvalidateの定義が推奨されています。
検証は、saveメソッドを使用する際に呼び出されますが、 model の options に {validate:true} を指定することで、saveする前に呼び出すことができます。また、検証に失敗するとデータベースに変更は保存しません。
var Chapter = Backbone.Model.extend({
validate: function(attrs, options) {
if (attrs.end < attrs.start) {
return "開始時間より終了時間のほうが早くなっているため保存出来ません";
}
}
});
var one = new Chapter({
title : "test"
});
one.on("invalid", function(model, error) {
console.error(model.get("title") + ": " + error);
});
one.set("start", 15);
one.set("end", 10, {validate:true});
console.log(one.get("end"));
one.save({
start: 15,
end: 10
});
Code language: JavaScript (javascript)
検証に失敗したモデルに対して invalid イベントが発生されます。
model.validationError
検証に最後に失敗した際のエラー情報が返ります。
one.validationError
Code language: JavaScript (javascript)
model.isValid
検証を直接実行します。
var Chapter = Backbone.Model.extend({
validate: function(attrs, options) {
if (attrs.end < attrs.start) {
return "開始時間より終了時間のほうが早くなっています";
}
}
});
var one = new Chapter({
title : "test"
});
one.set({
start: 15,
end: 10
});
if (!one.isValid()) {
console.error(one.get("title") + ": " + one.validationError);
}Code language: JavaScript (javascript)
model.url()
モデルに紐付けられるURLを返します。(サーバー上のリソース)
urlRoot属性がモデルクラスにない場合このメソッドは失敗します。
model.urlRoot or model.urlRoot()
モデルをHTTP経由のリソースの場合対応するURLが必要になってきます。その際に便利なのが。urlRootです。urlRootを定義することでモデルからURLを取得することができるようになります。また、このurlRootはコレクションに対しても有効です。
var Book = Backbone.Model.extend({urlRoot : '/books'});
var solaris = new Book({id: "1083-lem-solaris"});
console.log(solaris.url());Code language: JavaScript (javascript)
model.parse(response, options)
parseはデフォルトではresponseをそのまま戻り値として返すだけのメソッドです。extendで処理をオーバーライドして使用します。fetchやsaveを実行する際に、取得する前のデータをちょっと加工したりするのに使います。
Backbone.sync = function(method, model) {
console.log(method + ": " + JSON.stringify(model));
if (method == "read") {
model.set(model.parse({
data: {
"key1": 1,
"key2": 2,
"key3": 3
}
}));
}
};
var modelClass = Backbone.Model.extend({
parse: function (obj) {
return obj["data"];
}
});
var book = new modelClass({
id: 1,
title: "The Rough Riders",
author: "Theodore Roosevelt"
});
book.fetch();
console.log(book.get("key1"));
Code language: JavaScript (javascript)
また、モデル作成時のデフォルトのデータ指定時に、オプションに { parse: true } を指定すると、内部でparseが呼び出されデータを加工してからモデルにデータが追加されます。
var modelClass = Backbone.Model.extend({
parse: function (obj) {
return obj["data"];
}
});
var book = new modelClass({
data: {
id: 1,
title: "The Rough Riders",
author: "Theodore Roosevelt"
}
},
{
parse: true
});
console.log(book.get("title"));
Code language: JavaScript (javascript)
model.clone()
モデルのディープコピーを行います。モデルは完全に別々のものとして扱われます。
var a = new Backbone.Model({
hoge1: "hoge1",
hoge2: "hoge2",
hoge3: "hoge3"
});
var b = a.clone();
console.log(b.attributes);
Code language: JavaScript (javascript)
model.isNew()
サーバー上に保存されておらず、新しく作られたモデルである場合 true を返します。
var a = new Backbone.Model({
hoge1: "hoge1",
hoge2: "hoge2",
hoge3: "hoge3"
});
console.log(a.isNew());
Code language: JavaScript (javascript)
model.hasChanged([attribute])
モデルのプロパティである [attribute] に変更があった場合、 true を返します。
var a = new Backbone.Model({
hoge1: "hoge1",
hoge2: "hoge2",
hoge3: "hoge3"
});
a.on("change", function () {
if (a.hasChanged("hoge1")) {
console.log("hoge1に変更がありました");
}
if (a.hasChanged("hoge2")) {
console.log("hoge2に変更がありました");
}
if (a.hasChanged("hoge3")) {
console.log("hoge3に変更がありました");
}
});
a.set("hoge1", "1");
Code language: JavaScript (javascript)
model.changedAttributes([attributes])
modelの変更点を返します。[attributes]にハッシュを指定すると、そのハッシュが返ります。
var a = new Backbone.Model({
hoge1: "hoge1",
hoge2: "hoge2",
hoge3: "hoge3"
});
a.set("hoge3", "1");
console.log(a.changedAttributes());
Code language: JavaScript (javascript)
model.previous(attribute)
プロパティの値が変更される前の値を取得します。
var bill = new Backbone.Model({
name: "スーパーサイヤ人"
});
bill.on("change:name", function(model, name) {
console.log(bill.previous("name"));
console.log("↓");
console.log(name);
});
bill.set({name : "スーパーサイヤ人2"});
Code language: JavaScript (javascript)
model.previousAttributes()
モデルの変更前の全ての属性を返します。
前の状態に戻るとき(ロールバック)に便利です。
var bill = new Backbone.Model({
name: "スーパーサイヤ人"
});
bill.on("change", function(model) {
console.log(bill.previousAttributes());
console.log("↓");
console.log(bill.attributes);
});
bill.set({name : "スーパーサイヤ人2"});
Code language: JavaScript (javascript)
Backbone.Collection
やっとモデルが終わりました。覚えること多くて大変です。次に、コレクションを眺めていきます。
コレクションは、名前の通りコレクションで、何をコレクションするかというとモデル。複数のモデルを一つにまとめたものをコレクションと言うらしい。コレクションにも、モデルと同じようにイベントを登録したりすることが可能で、イベントの扱いがもっと簡単になるような概念です。
例えば、今まで人モデルにイベントを登録するには、一人一人にイベントを登録しなければいけませんでしたが、一人一人を一つのコレクションにまとめることによって、一括したイベント管理が行えるようになるということらしい。
Backbone.Collection.extend(properties, [classProperties])
モデルクラス同様、コレクションも独自のコレクションクラスを生成することができます。
collection.model
コレクションクラスには、モデルクラスを含めることが可能で、それを実現するにはcollection.modelをオーバーライドします。
var Book = Backbone.Model.extend({
defaults: {
key1: "1",
key2: "2"
},
hoge: function () {
console.log("hoge!");
}
});
var Library = Backbone.Collection.extend({
model: Book
});Code language: JavaScript (javascript)
また、modelを関数としてオーバライドすると、関数でモデルを生成することもできます。
var Library = Backbone.Collection.extend({
model: function(attrs, options) {
if (condition) {
return new PublicDocument(attrs, options);
} else {
return new PrivateDocument(attrs, options);
}
}
});Code language: JavaScript (javascript)
constructor / initialize new Collection([models], [options])
Collectionのconstructorによる初期化では、モデルを渡すことができます。
var Book = Backbone.Model.extend({
defaults: {
name: "",
price: "",
author: "",
genre: ""
}
});
var books = new Backbone.Collection([
[],
[],
[],
[]
], {
model: Book
});
console.log(books.models[0].attributes);
Code language: JavaScript (javascript)
collection.models
Collection内部への直接直接アクセスを行います。本来であればgetを使用するべきです。
console.log(books.models);Code language: CSS (css)
collection.toJSON()
これもモデルと同じように、JSON文字列にシリアライズ可能なハッシュを返します。
一見toJSONだけで文字列にできるように見えますができません。JSON.stringifyする際に暗黙的に呼ばれるので、あえて明示的に使用する必要はありません。
var collection = new Backbone.Collection([
{name: "Tim", age: 5},
{name: "Ida", age: 26},
{name: "Rob", age: 55}
]);
console.log(JSON.stringify(collection));Code language: JavaScript (javascript)
collection.sync(method, collection, [options])
サーバーへモデルの状態を保持する Backbone.syncを使用するためのオプションです。
Underscore Methods (28)
Underscoreの基本的なメソッドをコレクションに対して使用することができます。_を使わなくても、コレクションのメソッドとしてデリゲート(委任)されているのでそのままコレクションに対して使用できます。
var books = new Backbone.Collection([
{id:1, title: "aaa", group: "A", price: 1000},
{id:2, title: "bbb", group: "B", price: 1980},
{id:3, title: "ccc", group: "A", price: 980},
{id:4, title: "ddd", group: "B", price: 498}
]);
books.each(function (m) {
console.log(m);
});
books.map(function (m) {
return [ m.get("id"), m.get("title") ];
});
books.reduce(function (n, m, i, ms) {
n += m.get("price");
return n;
}, 0);
books.reduceRight(function (n, m, i, ms) {
n += m.get("price");
return n;
}, 0);
books.find(function (m) {
return m.get("group") == "A"
});
books.filter(function (m) {
return m.get("group") == "A"
});
books.where({
group: "B"
});
books.findWhere({
group: "A"
});
books.reject(function (m) {
return m.get("group") == "A"
});
books.every(function (m) {
return m.get("group") == "A"
});
books.some(function (m) {
return m.get("group") == "A"
});
books.contains(books.models[0]);
books.invoke(function(c){
c.log(this);
return this;
}, console);
books.pluck("title")
books.max(function (m) {
return m.get("price");
});
books.min(function (m) {
return m.get("price");
});
books.sortBy(function (m) {
return m.get("price");
});
books.groupBy(function (m) {
return m.get("group");
});
books. countBy(function (m) {
return m.get("group");
});
books.shuffle();
books.toArray();
books.size();
books.first();
books.initial();
books.initial(2);
books.last();
books.rest();
books.rest(2);
books.without(books.models[0]);
books.indexOf(books.models[1]);
books.lastIndexOf(books.models[1]);
books.sortedIndex(books.models[1], "price");
books.isEmpty();
books.isEmpty(books.models[0]);
books.chain();
Code language: JavaScript (javascript)
collection.add(models, [options])
コレクションにモデルを追加します。modelsにはそのままインスタンスとして生成済みのモデルを渡すこともできますが、ハッシュをそのまま渡すことで、内部でモデルを生成して追加させることもできます。モデルを追加するとcollectionには add イベントが発生します。
var ships = new Backbone.Collection();
ships.on("add", function(ship) {
console.log(ship.get("name")+" さんが追加されました");
});
ships.add([
{name: "佐藤"},
{name: "木村"},
{name: "吉田"},
{name: "吉田"}
]);
Code language: JavaScript (javascript)
collection.remove(models, [options])
指定したモデルをコレクションから削除します。
モデル削除時には、 remove イベントが collection に対して発生します。
var ships = new Backbone.Collection();
ships.on("add", function(ship) {
console.log(ship.get("name")+" さんが追加されました");
});
ships.on("remove", function(ship) {
console.log(ship.get("name")+" さんが消されました");
});
ships.add([
{name: "佐藤"},
{name: "木村"},
{name: "吉田"},
{name: "吉田"}
]);
ships.remove(ships.models[0]);
Code language: JavaScript (javascript)
collection.reset([models], [options])
コレクションをハッシュを元に作り直します。実質的にリセットです。
var ships = new Backbone.Collection();
ships.add([
{name: "佐藤"},
{name: "木村"},
{name: "吉田"},
{name: "吉田"}
]);
ships.reset(ships.toJSON());Code language: JavaScript (javascript)
collection.set(models, [options])
新しいコレクションのハッシュをセットします。オプションにdelete: falseを指定すると、既存のモデルは削除されることはありません。merge:false merge:true add:false 等もあるようです。
var ships = new Backbone.Collection([], {});
ships.add([
{name: "佐藤"},
{name: "木村"},
{name: "吉田"},
{name: "吉田"}
]);
ships.set([
{name: "田村"},
{name: "後藤"},
{name: "樋口"},
{name: "桑原"}
]);
var ships = new Backbone.Collection([]);
ships.add([
{name: "佐藤"},
{name: "木村"},
{name: "吉田"},
{name: "吉田"}
]);
ships.set([
{name: "田村"},
{name: "後藤"},
{name: "樋口"},
{name: "桑原"},
{name: "佐藤"},
{name: "木村"},
{name: "吉田"},
{name: "吉田"}
], { remove:false });
Code language: JavaScript (javascript)
collection.get(id)
コレクションからidまたはcidで指定されたモデルを取得します。
var ships = new Backbone.Collection([], {});
ships.add([
{name: "佐藤"},
{name: "木村"},
{name: "吉田"},
{name: "吉田"}
]);
ships.get("c396");
Code language: JavaScript (javascript)
collection.at(index)
コレクションで、indexから指定されたモデルを取得します。
ships.at(1);
Code language: JavaScript (javascript)
collection.push(model, [options])
コレクションの最後にモデルを追加します。
var ships = new Backbone.Collection([], {});
ships.add([
{name: "佐藤"},
{name: "木村"},
{name: "吉田"},
{name: "吉田"}
]);
ships.push({name: "室伏"});Code language: JavaScript (javascript)
collection.pop([options])
コレクションの最後からモデルを取り出して、コレクションから削除します。
var ships = new Backbone.Collection([], {});
ships.add([
{name: "佐藤"},
{name: "木村"},
{name: "吉田"},
{name: "吉田"}
]);
ships.pop();
Code language: JavaScript (javascript)
collection.unshift(model, [options])
コレクションの先頭にモデルを追加します。戻り値に追加したモデルが返ります。
var ships = new Backbone.Collection([], {});
ships.add([
{name: "佐藤"},
{name: "木村"},
{name: "吉田"},
{name: "吉田"}
]);
ships.unshift({name: "前田"});
Code language: JavaScript (javascript)
collection.shift([options])
コレクションの先頭からモデルを取り出して、削除します。
var ships = new Backbone.Collection([], {});
ships.add([
{name: "佐藤"},
{name: "木村"},
{name: "吉田"},
{name: "吉田"}
]);
ships.shift();
Code language: JavaScript (javascript)
collection.slice(begin, end)
begin番目からend番目までのモデルを切り出したものを返します。(コレクションから削除されるわけではありません)
var ships = new Backbone.Collection([], {});
ships.add([
{name: "佐藤"},
{name: "木村"},
{name: "吉田"},
{name: "吉田"}
]);
ships.slice(2, 3);
Code language: JavaScript (javascript)
collection.length
コレクションの保有しているモデルの数を返します。
var ships = new Backbone.Collection([], {});
ships.add([
{name: "佐藤"},
{name: "木村"},
{name: "吉田"},
{name: "吉田"}
]);
ships.length;Code language: JavaScript (javascript)
collection.comparator
コンパレータはデフォルトでは定義されていません。このコンパレータをオーバーライドし、コンパレータとして使用するキーを設定すると、そのキーによって自動的にモデルをソートしてくれるようになります。
var Chapter = Backbone.Model;
var chapters = new Backbone.Collection;
chapters.comparator = function(chapter) {
return chapter.get("page");
};
chapters.add(new Chapter({page: 9, title: "The End"}));
chapters.add(new Chapter({page: 5, title: "The Middle"}));
chapters.add(new Chapter({page: 1, title: "The Beginning"}));
console.log(chapters.pluck('title'));Code language: JavaScript (javascript)
collection.sort([options])
明示的にこれを呼び出す必要はありません。ソート機能を使いたい場合、コンパレータによる自動ソートの使用をおすすめします。もし自動ソートをやめたい場合は、オプションに、{sort: false}を指定します。
var Chapter = Backbone.Model;
var chapters = new Backbone.Collection;
chapters.sort({sort: false});
chapters.comparator = function(chapter) {
return chapter.get("page");
};
chapters.add(new Chapter({page: 9, title: "The End"}));
chapters.add(new Chapter({page: 5, title: "The Middle"}));
chapters.add(new Chapter({page: 1, title: "The Beginning"}));
console.log(chapters.pluck('title'));Code language: JavaScript (javascript)
collection.pluck(attribute)
var stooges = new Backbone.Collection([
{name: "Curly"},
{name: "Larry"},
{name: "Moe"}
]);
stooges.pluck("name");
Code language: JavaScript (javascript)
collection.where(attributes)
渡された{key:value}を持つモデルを複数返します。
var friends = new Backbone.Collection([
{name: "Athos", job: "Musketeer"},
{name: "Porthos", job: "Musketeer"},
{name: "Aramis", job: "Musketeer"},
{name: "d'Artagnan", job: "Guard"},
]);
friends.where({job: "Musketeer"});
Code language: JavaScript (javascript)
collection.findWhere(attributes)
渡された{key:value}を持つモデルで一番最初に見つかったモデルのみを返します。
var friends = new Backbone.Collection([
{name: "Athos", job: "Musketeer"},
{name: "Porthos", job: "Musketeer"},
{name: "Aramis", job: "Musketeer"},
{name: "d'Artagnan", job: "Guard"},
]);
friends.findWhere({job: "Musketeer"});
Code language: JavaScript (javascript)
collection.url or collection.url()
サーバー上のコレクションに結びつく独自のURLを設定します。
var Notes = Backbone.Collection.extend({
url: '/notes'
});
var Notes = Backbone.Collection.extend({
url: function() {
return this.document.url() + '/notes';
}
});Code language: JavaScript (javascript)
collection.parse(response, options)
fetchでサーバーからのレスポンスを得る際に、得たデータをコレクションとして取り入れる前に、少し加工してからモデルに取り入れるための処理を行います。
Backbone.sync = function(method, model) {
console.log(method + ": " + JSON.stringify(model));
if (method == "read") {
this.add(this.parse({data: {name: "test"}}));
}
};
var Tweets = Backbone.Collection.extend({
parse: function(response) {
console.log("parseが呼び出されました", response);
return response["data"];
}
});
var t = new Tweets([], {parse: true});
t.fetch();
console.log(t);
Code language: JavaScript (javascript)
urlを使用する場合はこのようにします。
Backbone.sync = function(method, model) {
console.log(method + ": " + model.url);
};
var accounts = new Backbone.Collection;
accounts.url = '/accounts';
accounts.fetch();Code language: JavaScript (javascript)
何も削除せずに、追加と更新のみを行う処理をしたい場合はこのようにします。
collection.fetch({remove: false});Code language: CSS (css)
また、ページネーションを表すのに
documents.fetch({data: {page: 3}});Code language: CSS (css)
が使用できるそうですが、どう使えばいいのか不明。。
collection.create(attributes, [options])
新しくモデルを作成すると同時に、データベース上にも新しく作成したモデルデータを登録します。
なるほど便利。
Backbone.sync = function(method, model) {
console.log(method + ": " + model.url);
};
var Book = Backbone.Model.extend({
url: "/document",
});
var Library = Backbone.Collection.extend({
url: "/document",
model: Book
});
var nypl = new Library;
var othello = nypl.create({
title: "Othello",
author: "William Shakespeare"
});Code language: JavaScript (javascript)
Backbone.Router
長い…長すぎる。上から下へ眺めるだけなのに何時間だったのだろうか。サンプルスクリプトをちまちま書いてたからか、今一番見たくないのはスクロールバー。
それはさておき、いよいよルーティングです。ブラウザのページを動的に切り替えるためのロジックなのでかなり期待大!です。
本題へ移ります。
ルーティングというのはブラウザのページ切り替えのURLのことです。ページを切り替えるとURLが代わり、URLひとつひとつに割り当てられているページが違う。当たり前のことではありますが、このURLはこれ、このURLはこっちと、振り分けていくことをルーティングと言います。
これまでのWebサービスは、ページを切り替える度に画面がフラッシュし、DNS解決やHTTPリクエストを送ったりとページ切り替えに少なからずストレスを感じずにはいられませんでした。Twitterがhashchangeによって動的なページ切り替えを実現はしましたが、URLが「https://hogehoge.com/#!hoge」というようにhash=#を使わなければならず、URLとしては少し見栄えが悪いものでした。
そこで、History API というものが登場し、HTTPリクエストを発生させなくても、URLを書き換えられるようになりました。URLを書き換えられるということは、URLを書き換えるタイミングで、HTMLもJavaScriptを使って書き換えるようにすれば、クライアントにとってあたかもページが高速に切り替わった印象を与えることができるようになります。
それに、ajaxの技術を組み合わせることで、リッチなWebアプリケーションの開発を行うことができます。そんなことを実現させてくれるのが、Backbone.Routerです。
Backbone.Routerを使用するには、 ページのロードが完了したら
Backbone.history.start();
または
Backbone.history.start({pushState: true});
によって、ルーティング初期URLとするために呼び出してください。
Backbone.Router.extend(properties, [classProperties])
特定のURLフラグメントが一致したときに実行されるアクションを定義した
ルーティングクラスを作成します。
先頭に / は必要ありません。
var WorkspaceRouter = Backbone.Router.extend({
routes: {
"help": "help",
"search/:query": "search",
"search/:query/p:page": "search"
},
help: function() {
console.log("ヘルプアクションです");
},
search: function(query, page) {
console.log("サーチアクションです");
}
});Code language: JavaScript (javascript)
router.routes
このハッシュオブジェクトによってルーティングを行います。
:param の部分がパラメータになり、 *splat の部分が /hoge/hoge/hoge/ と構造を表すことができます。
ルーティング時、あってもなくても良いような指定を行う場合は (/:optional) と書きます。
例えば
“search/:query/p:page”
は
search/obama/p2
にアクセスすることができ、:query にはobama、 :page には 2が入ります。
“file/*path”
は
file/nested/folder/file.txt
としてアクセスできます。
具体的には、ルーティングは
routes: {
"help/:page": "help",
"download/*path": "download",
"folder/:name": "openFolder",
"folder/:name-:mode": "openFolder"
}Code language: JavaScript (javascript)
のように書くことができ、
router.on("route:help", function(page) {
...
});Code language: JavaScript (javascript)
としてアクションを登録することもできます。
new Router([options])
オプションにハッシュを渡すことで初期化メソッドを実行することができます。
initialize: function(options) {
this.route("page/:number", "page", function(number){ ... });
this.route(/^(.*?)\\/open$/, "open");
},
open: function(id) { ... }Code language: JavaScript (javascript)
router.route(route, name, [callback])
手動でルーティングのルートを作成します。 router.routes による定義やアクションメソッドの定義はできません。
new Backbone.Router({
initialize: function(options) {
this.route("page/:number", "page", function(number){});
this.route(/^(.*?)\\/open$/, "open");
},
open: function(id) {
console.log("openがよばれました");
}
});Code language: JavaScript (javascript)
router.navigate(fragment, [options])
URLの変更とアクションの実行を行い、ページ遷移の挙動を振る舞います。
var RouterClass = Backbone.Router.extend({
routes: {
"help": "help",
"search/:query": "search",
"search/:query/p:page": "search"
},
help: function() {
console.log("ヘルプアクションです");
},
search: function(query, page) {
console.log("サーチアクションです");
}
});
var router = new RouterClass();
Backbone.history.start({pushState: true});
router.navigate("help", {trigger: true});
router.navigate("search", {trigger: true, replace: true});Code language: JavaScript (javascript)
Backbone.history
hashchange または pushState によるコールバック関数としての機能を果たします。
Hisory APIに対応していないブラウザの場合はhashchangeによるページ遷移を行います。
Backbone.history.start([options])
ルーティングが正しく設定してある場合において、 hashchangeイベントを監視するようにするには、
Backbone.history.start()
を実行します。
HTML5のpushStateを利用したい場合は、
Backbone.history.start({pushState: true});
を指定します。
ルートURLを指定するには、
Backbone.history.start({pushState: true, root: “/public/search/”})
とします。
Backbone.history.start() は 定義されたルートURLが一致するとtrueを返し、一致しない場合はfalseを返します。
hashchangeの場合、iframeに依存しているので、DOMの生成が完了しおわってから実行するようにしてください。
Backbone.sync
Backbone.syncがサーバーからデータを読み込んだり、保存したりする関数です。デフォルトでは、RESTfulなJQueryなAjaxが呼び出されるようになっていますが、この関数をオーバーライドすることによって、WebSocketだったり、localStorageだったりと、データストアを自由に切り替えることができます。
オーバーライドするには、
Backbone.sync = function(method, model) {
console.log(method + ": " + JSON.stringify(model));
};Code language: JavaScript (javascript)
とすることで、自由に処理を設定できます。console.logにて、どのようなmethodやmodelが呼ばれているのかを確認することができます。modelには model.urlが割り当てられていることがあるので、model.urlからURLを取得し、そのURLに対して通信を行うこともできます。
- method – the CRUD method (“create”, “read”, “update”, or “delete”)
- model – the model to be saved (or collection to be read)
- options – success and error callbacks, and all other jQuery request options
また、 モデルやコレクションがサーバーに通信を行うとき、 それぞれに対して、 request イベントが発生します。
RESTfulな実装の場合、各種HTTPメソッドはこのような割り当てになっています。
create → POST /collection
read → GET /collection[/id]
update → PUT /collection/id
delete → DELETE /collection/id
Backbone.ajax = function(request) { … };
ajaxをカスタマイズします。
Backbone.emulateHTTP = true
REST/HTTPをサポートしていない従来のWebサーバーを利用している場合、 Backbone.emulateHTTP を trueにすると、 X-HTTP-Method-Override header を付与し、 HTTPメソッドは _method に割り当てられます。
Backbone.emulateHTTP = true;
model.save(); Code language: JavaScript (javascript)
Backbone.emulateJSON = true
Backbone.emulateJSON を trueにすると、
JSONとしてエンコードのリクエストを扱うことができない従来のWebサーバで application/x-www-form-urlencoded として取得するようになります。
Backbone.View
モデルに登録したイベントのchangeイベントを監視して、モデルに変更があるタイミングでテンプレートエンジンを利用して画面を再描画します。
Backbone.View.extend(properties, [classProperties])
カスタムビュークラスの作成を開始します。
var DocumentRow = Backbone.View.extend({
tagName: "li",
className: "document-row",
events: {
"click .icon": "open",
"click .button.edit": "openEditDialog",
"click .button.delete": "destroy"
},
initialize: function() {
this.listenTo(this.model, "change", this.render);
}
render: function() {
}
});
Code language: JavaScript (javascript)
eventsには、
- tagName
- id
- className
- el
- event
が定義できます。
constructor / initialize
ビューインスタンスの生成を行います。
var DocumentRow = Backbone.View.extend({
tagName: "li",
className: "document-row",
events: {
"click .icon": "open",
"click .button.edit": "openEditDialog",
"click .button.delete": "destroy"
},
initialize: function() {
this.listenTo(this.model, "change", this.render);
}
render: function() {
}
});
var model = new Backbone.Model({
id: 1
name: "山田"
});
new DocumentRow({
model: model,
id: "document-row-" + model.id
});Code language: JavaScript (javascript)
view.el
ここに生成済みのdomが格納されます。
var ItemView = Backbone.View.extend({
tagName: 'li'
});
var BodyView = Backbone.View.extend({
el: 'body'
});
var item = new ItemView();
var body = new BodyView();
console.log(item.el + ' ' + body.el);Code language: JavaScript (javascript)
view.$el
DOM要素がjQueryでラッピングされたものです。
view.$el.show();
listView.$el.append(itemView.el);Code language: PHP (php)
view.setElement(element)
別のDOM要素にViewを適用したい場合に使用します。
view.attributes
view.elの属性のハッシュオブジェクトらしいが、undefinedしか帰ってこないため不明。
view.$(selector)
view.$で jQueryを利用することができます。
ui.Chapter = Backbone.View.extend({
serialize : function() {
return {
title: this.$(".title").text(),
start: this.$(".start-page").text(),
end: this.$(".end-page").text()
};
}
});Code language: JavaScript (javascript)
view.render()
デフォルトでは何もしませんが、this.elによって生成されたHTMLとテンプレートとモデルデータをレンダリングするようにこの関数をオーバーライドします。
レンダリング終了時にこの関数を呼び出すと良いです。
var Bookmark = Backbone.View.extend({
template: _.template(…),
render: function() {
this.$el.html(this.template(this.model.attributes));
return this;
}
});Code language: JavaScript (javascript)
ここではアンダースコアのテンプレートエンジンを使用していますが、 Mustache.js や Haml-js など様々なテンプレートエンジンがあるので、使ってみることをおすすめします。
view.remove()
ビューとビューの監視イベントを削除します。
delegateEvents([events])
var DocumentView = Backbone.View.extend({
events: {
"dblclick" : "open",
"click .icon.doc" : "select",
"contextmenu .icon.doc" : "showMenu",
"click .show_notes" : "toggleNotes",
"click .title .lock" : "editAccessLevel",
"mouseover .title .date" : "showTooltip"
},
render: function() {
this.$el.html(this.template(this.model.attributes));
return this;
},
open: function() {
window.open(this.model.get("viewer_url"));
},
select: function() {
this.model.set({selected: true});
},
...
});Code language: JavaScript (javascript)
undelegateEvents
ビューに委任されている全てのイベントを削除します。
サンプルスクリプト
よくわからなかったのでサンプルスクリプトを書いてみました。
var DocumentView = Backbone.View.extend({
template: _.template('<div><%= name %><div class="icon">開く</div><div class="button edit">編集</div><div class="button delete">削除</div></div>'),
events: {
"click .icon": "open",
"click .button.edit": "openEditDialog",
"click .button.delete": "destroy"
},
initialize: function() {
console.log(this.model, "を監視します");
this.listenTo(this.model, "change", this.render);
this.render();
},
render: function() {
console.log("描画を行います");
this.$el.html(this.template(this.model.attributes));
$(document.body).html("");
$(document.body).append(this.$el);
},
open: function () {
alert("open");
},
openEditDialog: function () {
alert("openEditDialog");
},
destroy: function () {
alert("destroy");
}
});
var model = new Backbone.Model({
id: 1,
name: "山田"
});
var view = new DocumentView({
model: model,
id: "document-row-" + model.id
});Code language: JavaScript (javascript)
モデルの変更によって動的にビューが書き換わっているはずなのに、イベントが死なない…
すごい…
また、サンプル中では、テンプレートを一つしか使ってないので、これをうまくいろんなテンプレートを使えるようにオブザーバを工夫する必要があります。
Utility
var backbone = Backbone.noConflict();
既存のbackboneオブジェクトを破壊せずに、もう一つbackboneを作成して使用します。
var localBackbone = Backbone.noConflict();
var model = localBackbone.Model.extend(...);Code language: JavaScript (javascript)
Backbone.$ = $;
jQueryのエイリアスです。
最後に
ようやく下まで眺め終わりました。眺めるレベルじゃない気もしますが、とりあえず….眠いです。おやすみなさい。