JotaBe JotaBe - 6 days ago 6
Javascript Question

Pass extra parameters to jquery ajax promise callback

I need to pass an extra parameter to the

.done
promise callback of a jquery ajax call:

$.post("MyUrl", JSON.stringify(data))
.done(onMyUrlLoaded);


The standard callback, would be like this:

function onMyUrlLoaded(data, textStatus, jqXHR) { /* function code */ };


But I need to pass an extra parameter to my callback, like this:

function onMyUrlLoaded(data, textStatus, jqXHR, extraParam) { /* code */ };


How can I do it?

NOTE: this question is not a duplicate, because it's specifically about promise callbacks. Besides this question is two years older than the one which is said to duplicate, and gives a much more thorough answer, and an specifica answer regarding promises.

Answer

I've discovered that it's really easy including a new indirection level, just like this:

var extraParam = 'xyz';

$.post("MyUrl", JSON.stringify(data))
        .done(function(a,b,c) { onMyUrlLoaded(a, b, c, extraParam); });

In this way, the callback will receive the extraParam, besides the three standard parameters.

Of course, this can also be done if the promise is stored in a variable, for example one returned by a function, like this:

function getUrl() {
  // some code ...
  var promise = $.post("MyUrl", JSON.stringify(data));
  return promise;
}

This can be invoked and used like this:

var promise = getUrl();
var extraParam = 'xyz';
promise.done(function(a,b,c) { onMyUrlLoaded(a, b, c, extraParam); });

There is a shorter syntax for doing this, which consist in using bind.

When you call bind in a function, you get a new function. The first parameter passed to bind will become this inside the body of teh return function. The additional parameters will be prepended to the original arguments.

The following code shows how to use bind. For TL;DR look the two last blocks of code

// To show the results in the page
var $log = $('#log');
var log = function(text) {
    $log.append(text+'<br/>');
};

// This returns a promise, and resolves it after the specified
// timeout. This behaves like a jQuery ajax call (but for the
// provided timeout)
var trigger = function(timeout) {
    log('<b>trigger</b> invoked');
    var deferred = $.Deferred();
    setTimeout(function() {
        log('<b>trigger</b> resolving promise');
        deferred.resolve('A','B');
    }, timeout);
    return deferred;
};

// This is the function we want to invoke
// The promise returns a and b - the extra params
// must be supplied in some way
var extraParams = function(extra1, extra2, a, b) {
    log('<b>extraParams</b> extra1:' + extra1);
    log('<b>extraParams</b> extra2:' + extra2);
    log('<b>extraParams</b> a:' + a);
    log('<b>extraParams</b> b:' + b);
};


// Doing it using indirection
trigger(500).then(function(a,b) {
  extraParams('extra1','extra2',a,b);
});

// Doing it using bind()
trigger(1200).then(
  extraParams.bind(this,'extra1','extra2')
);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="log">
</div>

Comments