English 中文(简体)
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.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;
  },
...

});




相关问题
selected text in iframe

How to get a selected text inside a iframe. I my page i m having a iframe which is editable true. So how can i get the selected text in that iframe.

How to fire event handlers on the link using javascript

I would like to click a link in my page using javascript. I would like to Fire event handlers on the link without navigating. How can this be done? This has to work both in firefox and Internet ...

How to Add script codes before the </body> tag ASP.NET

Heres the problem, In Masterpage, the google analytics code were pasted before the end of body tag. In ASPX page, I need to generate a script (google addItem tracker) using codebehind ClientScript ...

Clipboard access using Javascript - sans Flash?

Is there a reliable way to access the client machine s clipboard using Javascript? I continue to run into permissions issues when attempting to do this. How does Google Docs do this? Do they use ...

javascript debugging question

I have a large javascript which I didn t write but I need to use it and I m slowely going trough it trying to figure out what does it do and how, I m using alert to print out what it does but now I ...

Parsing date like twitter

I ve made a little forum and I want parse the date on newest posts like twitter, you know "posted 40 minutes ago ","posted 1 hour ago"... What s the best way ? Thanx.

热门标签