43

How do I update the returnHtml variable from within the anonymous success function?

function getPrice(productId, storeId) {
    var returnHtml = '';

    jQuery.ajax({
        url: "/includes/unit.jsp?" + params,
        cache: false,
        dataType: "html",
        success: function(html){
            returnHtml = html;
        }
    });

    return returnHtml;
}
Luffy
  • 1,317
  • 1
  • 19
  • 41
Shaun
  • 4,057
  • 7
  • 38
  • 48

3 Answers3

71

That is the wrong approach. The first A in AJAX is Asynchronous. That function returns before the AJAX call returns (or at least it can). So this is not an issue of scope. It is an issue of ordering. There are only two options:

  1. Make the AJAX call synchronous (not recommended) with the async: false option; or
  2. Change your way of thinking. Instead of returning HTML from the function you need to pass a callback to be called when the AJAX call succeeds.

As an example of (2):

function findPrice(productId, storeId, callback) {
    jQuery.ajax({
        url: "/includes/unit.jsp?" + params,
        cache: false,
        dataType: "html",
        success: function(html) {
            // Invoke the callback function, passing the html
            callback(productId, storeId, html);
        }
    });

    // Let the program continue while the html is fetched asynchronously
}

function receivePrice(productId, storeId, html) {
    // Now do something with the returned html
    alert("Product " + productId + " for storeId " + storeId + " received HTML " + html);
}

findPrice(23, 334, receivePrice);
ordonezalex
  • 2,645
  • 1
  • 20
  • 33
cletus
  • 616,129
  • 168
  • 910
  • 942
  • 1
    Gotchya - I figured i have to do that. but what if i had to do it? – Shaun Sep 22 '09 at 01:29
  • It's hard to answer that without knowing how you intended to use the getPrice() method. What's it used for? How is it used? It's code at that "outer" level that will need to adjust. – cletus Sep 22 '09 at 01:30
  • Ok i got it. I didn't realize that productId and storeId would be in the scope and I can actually pass that stuff into the call back. – Shaun Sep 22 '09 at 01:42
  • 2
    @cletus You cannot say not recommended. It is not recommended only when user needs not know that a request is made. But there are situations where async:false is needed. In a situation where user shall not be allowed to proceed or trigger another event, it is necessary. – Mohammed Shareef C Jul 25 '17 at 04:52
16

Short answer, you can't, the first A in AJAX stands for Asynchronous, which means the request is still going when you get to the return statement.

You can do it with a synchronous (non-async) request, but it's generally a Bad Thing

Something like the following oughta return the data.

function getPrice(productId, storeId) {
  var returnHtml = '';

  jQuery.ajax({
    url: "/includes/unit.jsp?" + params,
    async: false,
    cache: false,
    dataType: "html",
    success: function(html){
      returnHtml = html;
    }
  });

  return returnHtml;
}

BUT

Unless you really really need to be able to use the return value from test straight away, you'll be much better off passing a callback into test. Something like

function getPrice(productId, storeId, callback) {
  jQuery.ajax({
    url: "/includes/unit.jsp?" + params,
    async: true,
    cache: false,
    dataType: "html",
    success: function(html){
      callback(html);
    }
  });
}

//the you call it like
getPrice(x,y, function(html) {
    // do something with the html
}

Edit Sheesh, you guys are quicker to say what I said :-)

Dan F
  • 11,958
  • 3
  • 48
  • 72
13

Your anonymous function there does have access to the returnHtml variable in its scope, and so the code there is actually working as you'd expect. Where you're probably going wrong is in your return statement.

Remember that the A in AJAX stands for asynchronous, which means that it doesn't happen at the same time. For that reason, the line returnHtml = html is actually happening after you call return returnHtml;, so returnHtml is still an empty string.

It's hard to say what you should do to get this working as you want without seeing the rest of your code, but what you could do is add another callback to the function:

function getPrice(productId, storeId, callback) {
    jQuery.ajax({
        url: "/includes/unit.jsp?" + params,
        cache: false,
        dataType: "html",
        success: callback
    });
}

getPrice(5, 1, function(html) {
    alert(html);
});
Luffy
  • 1,317
  • 1
  • 19
  • 41
nickf
  • 537,072
  • 198
  • 649
  • 721