Search code examples
javascriptcallbackscoping

JavaScript Scoping - Passing callback to already defined function


The title is a bit weird, don't quite know the best way to explain it in a sentence...

At present there is an object with 3 functions; func, funcSuccess, and funcFailure. func contains a jQuery ajax request, with this.funcSuccess as the success callback, and funcError as the error callback. func is passed a callback for any success values to be passed back to, however this callback needs to be executed in the funcSuccess code.

Here's the code:

var Obj =

  { func: function (callback) {
      $.ajax(
        { type: 'POST'
        , url: '/func'
        , success: this.funcSuccess
        , error: this.funcError
        }
      )
    }

  , funcSuccess: function (res) {
      // THIS IS WHERE CALLBACK IS NEEDED
      callback(res.thing)
    }

  , funcError: function (res) {
      debug(res)
    }

  }

I'm wondering if there's a tidier way to do it rather than having:

var that = this
$.ajax(
  { type: 'POST'
  , url: '/func'
  , success: function (res) {
      that.funcSuccess(res)
    }
  , error: this.funcError
  }
)

Pretty sure I'm missing something obvious, just not quite with it today...


Solution

  • What about storing the callback explicitly in your object, so you don't have to worry about closure scopes:

    var Obj =
    
      { func: function (callback) {
          //this.callback = callback;
          $.ajax(
            { type: 'POST'
            , url: '/func'
            , success: $.proxy(this.funcSuccess, this, callback)
            , error: $.proxy(this.funcError, this)
            }
          )
        }
    
      , funcSuccess: function (callback, res) {
          callback(res.thing)
        }
    
      , funcError: function (res) {
          debug(res)
        }
    
      }
    

    Edit: I forgot to bind the callbacks to this. In JQuery you can do it with $.proxy, see changes above.

    Edit: A further tidy (jQuery 1.6 allows for this) with passing the callback as an argument to $.proxy, so no need to attach it to the current object.