开发者

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:

  1. 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.

  2. 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.

  3. 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.

  4. 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;
  },
...

});
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜