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

Answers


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"}); 

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"});

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.');
});

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

object.trigger("change");

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"}); 

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.


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().


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)


Need Your Help

Is std::vector<T> a `user-defined type`?

c++ c++11 language-lawyer template-specialization c++14

In 17.6.4.2.1/1 and 17.6.4.2.1/2 of the current draft standard restrictions are placed on specializations injected by users into namespace std.

How do I reimplement (or wrap) a syscall function on Linux?

c linux system-calls libc

Suppose I want to completely take over the open() system call, maybe to wrap the actual syscall and perform some logging. One way to do this is to use LD_PRELOAD to load a (user-made) shared object