Thomas
Thomas

Reputation: 5856

Backbone.js: Collection's "change" event isn't firing

I have a pretty simple collection, but I can't seem to bind to it's change event. In Chrome's console, I'm running:

var c = new AwesomeCollection();
c.bind("change", function(){
  console.log('Collection has changed.');
});

c.add({testModel: "Test"}); // Shouldn't this trigger the above log statement?

Since this is one of those things that can be difficult to track down, I doubt anybody knows off the top of their head what's going on (if so, great!). So, I'm asking two questions:

  1. Should the above code work as anticipated?
  2. If so, do you have any suggestions on how to track down where this would fail?

Thanks

Upvotes: 41

Views: 51306

Answers (8)

Bobby
Bobby

Reputation: 18315

The change event is only fired when one of the collections' models are modified. When a model is added to the collection the add event is fired.
See Backbone.js' Collection Documentation:

You can to bind "change" events to be notified when any model in the collection has been modified, listen for "add" and "remove" events[...]

To listen for when an add occurs modify your code to be

var c = new AwesomeCollection();
c.bind("add", function(){
  console.log('Collection has changed.');
});

c.add({testModel: "Test"}); 

Upvotes: 68

timDunham
timDunham

Reputation: 3318

No, that only raises the "add" event. It will raise the change event if you do this:

var c = new AwesomeCollection();
c.bind("change", function() {
  console.log('Collection has changed.');
});

var model = new Backbone.Model({testModel: "Test"});
c.add(model);
model.set({testModel: "ChangedTest"});

Upvotes: 11

Chris Dutrow
Chris Dutrow

Reputation: 50432

If you want to know when something of significance has been done with a collection, these are the events you probably want to listen to: change add remove reset

With respect to your example, this is what your code might look like:

var c = new AwesomeCollection();
c.bind('change add remove reset', function(){
    console.log('Collection has changed.');
});

Upvotes: 11

Gaurav Gupta
Gaurav Gupta

Reputation: 5416

I don't find it documented anywhere but the "all" event fires on all actions, including add, remove and change.

var c = new AwesomeCollection();
c.bind("all", function(){
  console.log('Something happened');
});

c.add({testModel: "Test"}); 

Upvotes: 1

Chicowitz
Chicowitz

Reputation: 5939

It may not be necessary in most cases, but you can manually trigger a change event on your object/collection:

object.trigger("change");

Upvotes: 5

I faced the same issue as yours on backbone 0.5.3.

Looking at Backbone.Collection.reset() implementation (which is called after a fetch() if you don't provide any "add" optional property), line 503 to 511 :

// When you have more items than you want to add or remove individually,
// you can reset the entire set with a new list of models, without firing
// any `added` or `removed` events. Fires `reset` when finished.
reset : function(models, options) {
  models  || (models = []);
  options || (options = {});
  this.each(this._removeReference);
  this._reset();
  this.add(models, {silent: true});
  if (!options.silent) this.trigger('reset', this, options);
  return this;
},

2 things are important here :

  this.add(models, {silent: true});

which means you won't have any "add" event triggered.

Second thing is the :

  if (!options.silent) this.trigger('reset', this, options);

Meaning that if you replace your code with :

var c = new AwesomeCollection();
c.bind("reset", function(){
  console.log('Collection has changed.');
}

c.add({testModel: "Test"}); // Shouldn't this trigger the above log statement?

It should work (worked for me)

Upvotes: 0

maxl0rd
maxl0rd

Reputation: 1446

Also, we cannot tell from your example, but a Collection must have its model property defined if you want to add models to it by simply passing an object. Otherwise, you must pass a model instance to add().

Upvotes: 0

malletjo
malletjo

Reputation: 1786

I hope AwesomeCollection is a BackboneCollection.

var AwesomeCollection = new Backbone.Collection();

AwesomeCollection.bind('add', function() {
    console.log('new object in the collection');
});

AwesomeCollection.add({something});

This should fire your event. If not, there is another problem somewhere else.

Edit: change can't be fired on add event like others said.

Upvotes: 0

Related Questions