38

What's the normal pure javascript (i.e. not JQuery) way to pass arguments into an anonymous onreadystatechange callback?

For example:

function doRequest(){
    /* Get an XMLHttpRequest in a platform independent way */    
    var xhttp = getXmlHttpRequestObject(); 

    var msg="show this message when done"; /* another variable to pass into callback */

     /* How do I pass 'msg' and 'xhttp' into this anonymous function as locals
       named 'x' and 'm'??? */
    xhttp.onreadychangestate=function(x,m)
    {
       if( x.readyState == 4 )
       {
           alert(m);
       }
    }
    /* do the open() and send() calls here.... */
}
Dennis Traub
  • 50,557
  • 7
  • 93
  • 108
Brian McFarland
  • 9,052
  • 6
  • 38
  • 56

3 Answers3

35

Javascript supports closures, so the anonymous function you wrote will be able to access xhttp and msg from the enclosing doRequest() scope.

If wanted to do this explicitly (say, if you want to define the callback function somewhere else in the code and reuse it), you could create a function that creates the callbacks. This also allows you to alias the variables to be accessible with different names (like x and m):

function createCallback(x, m) {
    return function() {
        /* Do whatever */
    };
}

and then in doRequest(), do xhttp.onreadystatechange = createCallback(xhttp, msg);

If all you wanted to do was 'rename' the variables, you can do this inline and anonymously:

xhttp.onreadystatechange = (function(x, m) {
    return function() {
        /* Do stuff */
    }
})(xhttp, msg);
George
  • 4,147
  • 24
  • 33
  • 2
    Thanks. This answer prompted me to learn a lot more about Javascript. Really all I needed to know was how the closures work. – Brian McFarland Dec 21 '11 at 15:17
  • http.onreadystatechange = function(){ var xmlHttp = this; if(xmlHttp.status == 200){ console.log("We got it!"); } }; – Abbas Jan 25 '18 at 09:09
20

Part of the above answer didn't work for me. First, for a separate callBack function having no parameters:

 xhttp.onreadystatechange = callBack;   //works; the function's NAME is required

Now suppose the callBack function is modified to receive some parameters:

 xhttp.onreadystatechange = callBack(x,m); //didn't work, and didn't know why
 xhttp.onreadystatechange = createCallback(xhttp,msg); //bad part of above Answer

However, elsewhere here at StackOverflow someone explained that it had to do with the need to assign a "function reference" instead of a "function call" to onreadystatechange (like the NAME above is a function reference), and posted a solution:

 xhttp.onreadystatechange = function(){callBack(x,m);}; //works

I came here to add something to that other Answer, but now can't find it. So I might as well add it here. In my own code I was using both local variables and global variables, and discovered something that didn't seem to work right, but now that I know what actually happened, a Word Of Warning seems appropriate. Assume "g" is a global variable:

 xhttp.onreadystatechange = function(){callBack(x,g);};//anonymous function works

The function reference is assigned to onreadystatechange at some point in time (T0), and the callBack function is called called at a different time (T1). Well, the value of global variable "g" at T1 is the value that gets passed to the callBack function, NOT the value of "g" when the function reference was assigned at T0. Don't let this bite you like it bit me! (Local variables generally don't have this problem because they are usually out of scope at T1, so JavaScript has to use their existing values at T0, when setting the parameter-values of the anonymous function.)

13

Never too late! :-)

Instead of passing data using arguments in xhttp.onreadystatechange which is somewhat complicated, one can just add properties to the xhr object itself.

For instance:

var m = "Hello!";
var xhttp = new XMLHttpRequest();
xhttp.m = m;
xhttp.onreadystatechange = function()
{
    var x, m;
    x = this;
    m = x.m;
    if ((x.readyState == 4) && (x.status == 200))
    {
        alert(m);
    }
};
// ...
Simon Hi
  • 2,838
  • 1
  • 17
  • 17
  • This worked for me. I added my callback function to the new XMLHttpRequest. So to be clear. It's perfectly safe to say "myXMLHttpRequest.anythingIWant = anything;" and it'll just remember that value? – Joe C Dec 12 '19 at 03:52
  • @Joe C yes, "myXMLHttpRequest.anythingIWant" value is "anything" as long as "myXMLHttpRequest" exists, including inside the callback function. – Simon Hi Dec 18 '19 at 20:21
  • This worked for me. Instead of this, used the variable directly xhr.value = response; And the inside the onreadystatechange function, accessed it via xhr.value – akshay May 06 '20 at 06:19