バックボーンアプリには、モデルに裏打ちされたビューがあり、モデルをコレクションに保存しています。ページにはこれらのビューがいくつかあり、一度に選択できるのは1つだけです。したがって、これらのビューのコレクションを含む別のビューがあります。ユーザーがフォーカスされていないビューをクリックすると、ビューはモデルの「フォーカスされた」属性をtrueに設定します。モデルのセットは、ビュー自体によって処理される変更イベント($ elにフォーカスされたクラスを追加する)と、コレクション内のすべてのビューをループし、フォーカスされているビューのフォーカスを解除するViewCollectionビューをトリガーします(クリックしたばかりのもの以外)。
適度な速度でクリックすると、これはすべてうまく機能します。ただし、非常に速くクリックすると、モデルの設定された動作に矛盾が見られます。つまり、モデルの「focused」属性をtrueに設定すると、次のクリックイベントは、そのモデルの「focused」属性がまだfalseであることを示します。
コード:
var M = Backbone.Model.extend({
defaults : {
"name" : "",
"focused" : true
}
}),
L = Backbone.Collection.extend({
model : M
}),
V = Backbone.View.extend({
events : {
"click .button" : "focus"
}
initialize: function() {
this.model.bind("change:focused", this.handleFocusChange, this)
},
focus: function() {
console.log("Focus: " + this.model.get("name") + ".focused = " + this.model.get("focused"));
if (this.model.get("focused")) {
return;
}
this.model.set({focused: true}); // triggers change event
this.model.save(this.model);
console.log("Focus: " + this.model.get("name") + ".focused = " + this.model.get("focused"));
},
unfocus: function() {
console.log("Unfocus: " + this.model.get("name") + ".focused = " + this.model.get("focused"));
if (!this.model.get("focused")) {
return;
}
this.model.set({focused: false}); // triggers change event
this.model.save(this.model);
console.log("Unfocus: " + this.model.get("name") + ".focused = " + this.model.get("focused"));
},
handleFocusChange: function(model, focused) {
if (focused) {
console.log("Handling focus change on " + this.model.get("name") + ", " + this.model.cid);
this.$('.button').addClass("focused");
} else {
console.log("Handling unfocus change on " + this.model.get("nickname") + ", " + this.model.cid);
this.$('.button').removeClass("focused");
}
}
}),
ViewCollection = Backbone.View.extend({
initialize : function(options) {
_.bindAll(this, 'initViews');
this._views = [];
this.collection.each(this.initViews);
},
initViews : function(model) {
var view = new V({
model : model
});
this._views.push(view);
view.model.bind("change:focused", this.focusChanged, this);
},
focusChanged: function(changed, focused) {
if (!focused) {
return;
}
_.each(this._views, function(view) {
if (view.model.id !== changed.id) {
view.unfocus();
}
});
}
})
上記のログステートメントからの出力は次のとおりです。
Click
Focus: A.focused = false
Handling focus change on A, c10
Unfocus: B.focused = false
Unfocus: C.focused = false
Unfocus: D.focused = true
Handling ufocus change on D, c7
Unfocus: D.focused = false
Focus: A.focused = true <-- good!
Click
Focus: C.focused = false
Handling focus change on C, c9
Unfocus: B.focused = false
Unfocus: A.focused = false <-- bad!
Unfocus: D.focused = false
Focus: C.focused = true
ご覧のとおり、最初にAをクリックし、次にCをクリックしました。変更されたイベントが発生し、ビューとコレクションの両方が適切に動作しました。ただし、2回目のクリックでは、Aの「focused」属性はtrueであるはずのときにfalseになります。繰り返しますが、これは私がビューを非常に速くクリックしたときにのみ発生します。通常の速度でクリックすると、この問題を再現できません。
どんな助けでも大歓迎です!