Skip to main content

Backbone Events

· 6 min read

Backbone events are a powerful way to write responsive user interfaces with fewer lines of codes. This article attempts to give a detailed breakdown of the events and the parameters available for the callback functions.

The results in this article are applicable for version 1.2.3 of Backbone.js

The test is performed by instantiating instances of ExperimentModel extended from Backbone.Model and ExperimentCollection extended from Backbone.Collection.

The model is first added to the collection to test "add" on the collection and then a properrty is set on the model.

var expModelA = new ExperimentModel({ id: 'a' });
var expCollA = new ExperimentCollection();

Add

expCollA.on('add', function (model, collection, obj) {
...
});
expModelA.on('add', function (model, collection, obj) {
...
});
expCollA.add(expModelA);

In both of the callback functions 3 parameters are passed:

  1. model
The model being added to the collection.
  1. collection

The collection after the model is added.

  1. operation object

A map containing the following keys (and values):

  • merge (false)
  • add (true)
  • remove (false)
EventModelCollection
add

Event is triggered on the model and collection (in this sequence) when the model is added to the collection.

Remove

expModelA.on('remove', function (model, collection, obj) {
...
});
expCollA.on('remove', function (model, collection, obj) {
...
});
expCollA.remove(expModelA);

In both of the callback functions 3 parameters are passed:

  1. model
The model being added to the collection.
  1. collection

The collection after the model is added.

  1. operation object

A map containing the following key (and value):

  • index (the position in the collection of the model that was removed).

EventModelCollection
remove

Event is triggered on the model and collection (in this sequence) when the model is removed from the collection.

Update

expCollA.on('update', function (collection, obj) {
...
});
expCollA.add(expModelA);
expCollA.remove(expModelA);

The update event is only called on the collection when a model is added to or removed from the collection. Its callback function receives two parameters:

  1. collection

The collection after the model is added.

  1. operation object

A map that contains different keys and values depending on the type of operation (add or remove). See Add and Remove for details.

EventModelCollection
update

Event is triggered on the collection after add and remove

Sort

expCollA.on('sort', function (collection, obj) {
...
});

This event can be triggered when a model is added to/removed from the collection. It can also be triggered by a call to sort()

collection

The collection after the model is added.

operation object

A map containing the following keys:

  • merge (boolean)
  • add (boolean)
  • remove (boolean)

The values in this map indicate the operation that occurred that triggered the event. If this event was triggered by invocation of sort, this map will be empty.

EventModelCollection
sort

Change

expModelA.on('change', function (model) {
...
});
expCollA.on('change', function (model) {
...
});

This event is triggered on both the model that was changed, and the collection that the model is in.

model
The model that was changed.
EventModelCollection
change

Reset

expCollA.on('reset', function (collection, obj) {
...
});
expCollA.reset();

The reset event is invoked by the reset() method. This method accepts an optional parameter that is the list of models used to replace the collection. The callback function receives 2 parameters:

collection
The collection after the reset operation is completed.
options

This object has the previousModels property that holds the models that were replaced by the reset() operation.

EventModelCollection
reset

(2023 February note: The script below was supposed to update the tables in this page. But since the change to Docusaurus, the needed scripts are no longer available on the page so the code does not work anymore. They are left here for posterity.)

<script src="/js/lib/jquery.min.js"></script>

<script src="/js/lib/underscore.min.js"></script>

<script src="/js/lib/backbone.min.js"></script>

$(document).ready(function () {
var tick = '&#x2713';
var ExperimentModel = Backbone.Model.extend({
defaults: {
name: null
},
validate: function (attrs) {
if (!attrs.name) {
return 'name is required';
}
}
});
var ExperimentCollection = Backbone.Collection.extend({
model: ExperimentModel
});

console.info('Instantiating ExperimentModel A', expModelA);
var expModelA = new ExperimentModel({
id: 'a',
name: 'Alpha'
});
console.info('Instantiating ExperimentCollection A', expCollA);
var expCollA = new ExperimentCollection();
expCollA.comparator = 'name';

expModelA.on('change', function (m) {
console.log('Model: change', m.toJSON(), arguments);
$('.change-model').html(tick);
});
expModelA.on('sort', function () {
console.log('Model: sort', arguments);
});
expModelA.on('reset', function () {
console.log('Model: reset', arguments);
});
expModelA.on('update', function () {
console.log('Model: update', arguments);
$('.update-model').html(tick);
});
expModelA.on('add', function (m, c, o) {
console.log('Model: add', m.toJSON(), c.length, o);
$('.add-model').html(tick);
});
expModelA.on('remove', function (m, c, o) {
console.log('Model: remove', m.toJSON(), c.length, o);
$('.remove-model').html(tick);
});

expCollA.on('change', function (m) {
console.log('Collection: change', m.toJSON(), arguments);
$('.change-collection').html(tick);
});
expCollA.on('sort', function (c, o) {
console.log('Collection: sort', c.length, o);
$('.sort-collection').html(tick);
});
expCollA.on('reset', function (c, o) {
console.log('Collection: reset', c.length, o);
$('.reset-collection').html(tick);
});
expCollA.on('update', function (c, o) {
console.log('Collection: update', c.length, o);
$('.update-collection').html(tick);
if (o.add) { console.log('ADD'); } else { console.log('REMOVE'); }
});
expCollA.on('add', function (m, c, o) {
console.log('Collection: add', m.toJSON(), c.length, o);
$('.add-collection').html(tick);
});
expCollA.on('remove', function (m, c, o) {
console.log('Collection: remove', m.toJSON(), c.length, o);
$('.remove-collection').html(tick);
});

//Steps
console.info('Adding model A to collection A');
expCollA.add(expModelA);
console.info('Setting name on model A');
expModelA.set('name', 'Experiment A');

console.info('Removing model A from collection A');
expCollA.remove(expModelA);
console.info('Unsetting name on model A');
expModelA.unset('name');

console.log('Adding model A back to collection A');
expCollA.add(expModelA);
console.info('Changing name of model A');
expModelA.set('name', 'Aloha');
console.info('Resetting collection A');
expCollA.reset([
new ExperimentModel({ id: 'd', name: 'Delta' }),
new ExperimentModel({ id: 'c', name: 'Charlie' }),
new ExperimentModel({ id: 'b', name: 'Bravo' })
]);
console.warn('Final length:', expCollA.length);
});