Strange behavior with "this" in Backbone.js when binding to "add"/"remove" in a collection
I have the following two views based on Backbone.js
pg.views.ItemList = Backbone.View.extend({
tagName: "div",
className: "items",
initialize: function() {
_.bindAll(this, 'addOne', 'addSelected')
Items.bind('add', this.addOne);
Items.fetch();
},
// REMOVED
addOne: function(Item) {
console.log($(this.el));
var view = new pg.views.Item({model: Item});
$(this.el).append(view.render().el);
},
addSelected: function(ItemList) {
_.each(ItemList, this.addOne);
return this.el;
},
// REMOVED
});
pg.views.Section = Backbone.View.extend({
tagName: "section",
sectionTemplate: _.template($('#section-template').html()),
events: {
// REMOVED
},
initialize: function() {
_.bindAll(this, 'render', 'close', 'addItemToSection', 'removeItemFromSection');
this.model.bind('change', this.render);
this.model.view = this;
Items = new pg.collections.ItemList;
},
render: function() {
$(this.el).html(this.sectionTemplate(this.model开发者_JS百科.toJSON()));
this.setContent();
Items.bind('add', this.addItemToSection); // "add" event bind
Items.bind('remove', this.removeItemFromSection); // "remove" event bind
this.addItems();
return this;
},
addItems: function() {
var ids = this.model.get('items');
var view = new pg.views.ItemList;
var items = _.map(ids, function(id){ return Items.get(id); });
$(this.el).append(view.addSelected(items));
},
// FUNCTIONS REMOVED
setContent: function() {
var title = this.model.get('title');
this.$('.title').text(title);
this.title = this.$('.title-input');
this.title.val(title);
},
addItemToSection: function(Item) {
console.log(this.model.get('title'));
// REMOVED
},
removeItemFromSection: function(Item) {
console.log(this.model.get('title'));
// REMOVED
}
});
Here is the problem I am encountering.
I have a view where a user creates two sections, lets say that they are called "section1" and "section2". These names are used in their "title" attribute.
Here is the strange behavior I am observing:
When a user is in "section1" and adds and item, the "add" bind event is triggered, this results in "section2" being written to the console.
When a user is in "section1" and adds and item, the "remove" bind event is triggered, this results in "section1" being written to the console.
When a user is in "section2" and adds and item, the "add" bind event is triggered, this results in "section2" being written to the console.
When a user is in "section2" and adds and item, the "remove" bind event is triggered, this results in "section2" and then "section1" being written to the console.
If I am binding "add" inside the "pg.views.Section" view using "this.addItemToSection", shouldn't it only call the "addItemToSection" block inside that instance?
The only line that I can see "redefining" the "this" is the "add" bind in the initialize block of "pg.views.ItemList". If that line is the culprit, how do I prevent it from redefining the "this" on the "add" bind for "section1"?
I think this is a global problem, pun intended ;) You are calling everything on Items
which firstly has been declared with var - (bad practice) implies it'll be bound to the window object. And you use the same variable reference in an another view! So both will get call because they refer to the same object!!!! You can have as many 'local' instances you want by binding to 'this'. Try the following changes, I guess they should work.
pg.views.ItemList = Backbone.View.extend({
tagName: "div",
className: "items",
initialize: function() {
_.bindAll(this, 'addOne', 'addSelected')
this.myItems = new pg.collections.ItemList(); //create local reference
this.myItems.bind('add', this.addOne);
this.myItems.fetch();
},
...
});
pg.views.Section = Backbone.View.extend({
tagName: "section",
initialize: function() {
_.bindAll(this, 'render', 'close', 'addItemToSection', 'removeItemFromSection');
this.model.bind('change', this.render);
this.model.view = this;
this.mySectionItems = new pg.collections.ItemList; //add to 'this'
},
render: function() {
$(this.el).html(this.sectionTemplate(this.model.toJSON()));
this.setContent();
this.mySectionItems.bind('add', this.addItemToSection); // "add" event bind
this.mySectionItems.bind('remove', this.removeItemFromSection); // "remove" event bind
this.addItems();
return this;
},
...
});
精彩评论