Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Backbone: Correct way of passing 'this' reference to anon functions in success/error callbacks

Given the backbone view function below, what is the correct way of passing this (i.e. the current view) to the anonymous function defined in the callbacks?

addSomething: function(e) {
    var newSomething= this.model.somethings.create({
        someProperty: xxx
    }, {
        success: function(m, response) {
            this.doSomething(); //***HERE****
        },
        error: function(m, response) {
            //Error
        }
    });
},

Without and changes, the this in the anon function is set to the window.

I can a set a reference like this:

var thisView = this;

and then just refer to thisView instead of this in the anon function, but this doesn't seem very elegant. Is there a better way?

like image 861
UpTheCreek Avatar asked Sep 29 '11 14:09

UpTheCreek


4 Answers

In order to better organize my code and work around this problem, I never put success and error callbacks directly in-line with my calls. I always split them out to their own functions. This let's me keep the code clean and also use the _.bindAll method to ensure I have the correct context for this.

SomeView = Backbone.View.extend({
  initialize: function(){
    _.bindAll(this, "createSuccess", "createError");
  },

  addSomething: function(e) {
    var newSomething= this.model.somethings.create({someProperty: xxx}, {
      success: this.createSuccess,
      error: this.createError
    });
  },

  createSuccess: function(m, response) {
    this.doSomething();
  },

  createError: function(m, response) {
    //Error
  }
});
like image 155
Derick Bailey Avatar answered Oct 05 '22 20:10

Derick Bailey


You can use call:

this.doSomething.call(this);

Or send whatever you want this to be in doSomething

like image 21
Joe Avatar answered Oct 05 '22 21:10

Joe


You could also use the that convention:

addSomething: function(e) {

var that = this;

var newSomething= this.model.somethings.create({
        someProperty: xxx
    }, {
        success: function(m, response) {
            that.doSomething(); //***THAT HERE****
        },
        error: function(m, response) {
            //Error
        }
    });
}

This is quite a common pattern in javascript especially when context is lost with nested functions. Nested functions do have access to the variables in the outer function and hence it works.

Derick's approach makes the code cleaner, irrespective of the fact of having extra functions but if you don't want them use 'that' ;)

like image 25
PhD Avatar answered Oct 05 '22 20:10

PhD


Backbone has a builtin way to handle this: the 'context' attribute.

this.model.destroy({
    success: function (model, resp, options) {
        model.releaseLock();
        window.location.href = this.getURLForModelID(model.get('id'));
    },
    error: function (model, resp, options) {
        this.displayError(resp.message);
    },
    context: this
});
like image 42
david.muffley Avatar answered Oct 05 '22 20:10

david.muffley