14

What are the differences among .on, .listenTo, and .bind?

I tested them here and they seem do the same thing: a callback.

var NewStatusView = Backbone.View.extend({

    events: {
        "submit form": "addStatus"
    },

    initialize: function(options) {

        // using .on
        //this.collection.on("add", this.clearInput, this);

        // or using bind: 
        //_.bindAll(this, 'addStatus', 'clearInput');
        //this.collection.bind('add', this.clearInput);

        // or using listenTo: 
         _.bindAll(this, 'addStatus', 'clearInput');
        this.listenTo(this.collection, 'add', this.clearInput) ;
    },

    addStatus: function(e) {
        e.preventDefault();
        this.collection.create({ text: this.$('textarea').val() });
    },

    clearInput: function() {
        this.$('textarea').val('');
    }
});

When and in scenario to use which is the best?

Emile Bergeron
  • 17,074
  • 5
  • 83
  • 129
Run
  • 54,938
  • 169
  • 450
  • 748
  • 1
    Have you read the documentation or the source code? See https://github.com/jashkenas/backbone/blob/master/backbone.js#L233 – Ram Dec 19 '13 at 06:44
  • 1
    Have you visited the linked page on github? – Ram Dec 19 '13 at 07:44
  • `Events.bind = Events.on;Events.unbind = Events.off;` does it mean that `bind` is the same as `on`? – Run Dec 19 '13 at 08:38
  • 3
    Yes, both methods do the same thing. Check the first line http://backbonejs.org/#Events-on – Ram Dec 19 '13 at 08:41

1 Answers1

23

It's usually best to use listenTo()

From Backbone Essentials by Addy Osmani:

While on() and off() add callbacks directly to an observed object, listenTo() tells an object to listen for events on another object, allowing the listener to keep track of the events for which it is listening. stopListening() can subsequently be called on the listener to tell it to stop listening for events:

var a = _.extend({}, Backbone.Events);
var b = _.extend({}, Backbone.Events);
var c = _.extend({}, Backbone.Events);

// add listeners to A for events on B and C
a.listenTo(b, 'anything', function(event){ console.log("anything happened"); });
a.listenTo(c, 'everything', function(event){ console.log("everything happened"); });

// trigger an event
b.trigger('anything'); // logs: anything happened

// stop listening
a.stopListening();

// A does not receive these events
b.trigger('anything');
c.trigger('everything');

If you use on and off and remove views and their corresponding models at the same time, there are generally no problems. But a problem arises when you remove a view that had registered to be notified about events on a model, but you don’t remove the model or call off to remove the view’s event handler. Since the model has a reference to the view’s callback function, the JavaScript garbage collector cannot remove the view from memory. This is called a ghost view and is a form of memory leak which is common since the models generally tend to outlive the corresponding views during an application’s lifecycle. For details on the topic and a solution, check this excellent article by Derick Bailey.

Practically, every on called on an object also requires an off to be called in order for the garbage collector to do its job. listenTo() changes that, allowing Views to bind to Model notifications and unbind from all of them with just one call - stopListening().

The default implementation of View.remove() makes a call to stopListening(), ensuring that any listeners bound using listenTo() are unbound before the view is destroyed.

var view = new Backbone.View();
var b = _.extend({}, Backbone.Events);

view.listenTo(b, 'all', function(){ console.log(true); });
b.trigger('anything');  // logs: true

view.listenTo(b, 'all', function(){ console.log(false); });
view.remove(); // stopListening() implicitly called
b.trigger('anything');  // does not log anything
Emile Bergeron
  • 17,074
  • 5
  • 83
  • 129
  • 3
    I didn't upvote because no mention of bind! I don't care for the use of bind because there's the mental namespace conflict with _.bind and _.bindAll, why Jeremy did you choose bind for Events also – Alexander Mills Jul 02 '15 at 01:10