Pregunta

This one should be simple, but it's not and it's giving me headache.

I copy/pasted a fairly simple "Hello Backbone" code, and simplified it some more, to get this:

(function($){
  var Item = Backbone.Model.extend({
    defaults: {
      part1: 'hello',
      part2: 'world'
    },

    initialize: function() {
      //console.log("initialize item");
    }
  });

  var List = Backbone.Collection.extend({
    model: Item,

    initialize: function() {
      //console.log("initialize list");
    }
  });

  var ListView = Backbone.View.extend({
    //el: $('body'), // el attaches to existing element

    initialize: function(){
      _.bindAll(this, 'render'); // every function that uses 'this' as the current object should be in here

      this.collection = new List();

      this.render();
    },
    render: function(){
      //console.log("listview render");
    },
  });

  var listView = new ListView();

  var item1 = new Item();
  listView.collection.add(item1);

  console.dir("Emptying collection...");
  listView.collection.each(function (item) {
    console.dir("Removing model cid:" + item.cid);
    listView.collection.remove(item);
  })

  var item2 = new Item();
  listView.collection.add(item2);

  var item3 = new Item();
  listView.collection.add(item3);

  console.dir("Emptying collection...");
  listView.collection.each(function (item) {
    console.dir("Removing model cid:" + item.cid);
    listView.collection.remove(item);
  })

  console.log(listView.collection.length);
})(jQuery);

First part is actually some backbone boilerplate stuff, and the last one should:

  • add a model to collection
  • clear collection
  • add two models to collection
  • clear collection

Finally, listView.collection.length should be 0, but it's not. There is one model left.

What I see from console log, the listView.collection.each(function (item) { ... }) is not doing what it should be doing, because only one item is removed in the second collection iteration, instead of two items.

So, am I doing something wrong or there is a bug here somewhere?

UPDATE: here's the jsfiddle

¿Fue útil?

Solución

You're altering a list of elements (listView.collection.remove(item)) while iterating over it, which usually leads to Bad Things™ Here's a simplified test case : http://jsfiddle.net/nikoshr/Xx9uw/

Either clone your list of models before removing them:

_.each(_.clone(listView.collection.models), function (item) {
    console.log("Removing model cid:" + item.cid);
    listView.collection.remove(item);
});

http://jsfiddle.net/nikoshr/Xx9uw/2/

Or use collection.reset :

listView.collection.reset();

http://jsfiddle.net/nikoshr/Xx9uw/3/

Otros consejos

The problem is that you're never creating a collection.

var list = new List(); var listView = new ListView({collection: list});

The moment I saw @nikoshr's answer I knew I was a sucker. Again. I'm repeating the same mistake throughout different languages, C/C++ (usually yields ye-olde-segfault), Java, C#, etc... and now JS/BB.

Damn.

In addition to nikoshr's answer, I found this collection-based solution that could avoid classic iteration (in C# one can use linq extensions for that purpose):

this.collection
  .forEach(function (item) {
    item.destroy()
  });

Conveniently, Underscore gives you an option to filter out just the models you really need:

this.collection
  .where({ YourAttribute: YourValue, YourOtherAttribute: YourOtherValue })
  .forEach(function (item) {
    item.destroy()
  });
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top