0

I have an issue with the below code:

the jQuery.each is speeding on without waiting for the JSON request to finish. As a result, the 'thisVariationID' and 'thisOrderID' variables are being reset by the latest iteration of a loop before they can be used in the slower getJSON function.

Is there a way to make each iteration of the the .each wait until completion of the getJSON request and callback function before moving on to the next iteration?

$.each($('.checkStatus'), function(){
            thisVariationID = $(this).attr('data-id');
            thisOrderID = $(this).attr('id');
            $.getJSON(jsonURL+'?orderID='+thisOrderID+'&variationID='+thisVariationID+'&callback=?', function(data){
                if (data.response = 'success'){
                //show the tick. allow the booking to go through
                    $('#loadingSML'+thisVariationID).hide();
                    $('#tick'+thisVariationID).show();
                }else{
                //show the cross. Do not allow the booking to be made
                    $('#loadingSML'+thisVariationID).hide();
                    $('#cross'+thisVariationID).hide();
                    $('#unableToReserveError').slideDown();
                    //disable the form
                    $('#OrderForm_OrderForm input').attr('disabled','disabled');
                }
            })
        })
Fraser
  • 14,036
  • 22
  • 73
  • 118
  • Have a look here: [http://stackoverflow.com/questions/1761417/jquery-possible-to-wait-for-get-to-finish-loading-before-continuing][1] [1]: http://stackoverflow.com/questions/1761417/jquery-possible-to-wait-for-get-to-finish-loading-before-continuing – Pasha Immortals Jun 05 '12 at 04:34

4 Answers4

3

You need to use either 1). Non-async calls (as illustrated in the following code):

$.ajax({
    url:jsonURL, 
    dataType:'json', 
    data:{orderID:thisOrderID, variationID:thisVariationID},
    async:false,
    success:function()
    {
        // do stuff.
    }

2). If you're using jsonp cross site, you'd need to chain your calls instead of using each. Use each to build a data array, then start calling the json, with each iteration using the data from before in the callback.


Added: For op clarification, a cross site implementation, which sets up a list of items to process and then processes them individually.

I've broken into mostly Plain Old Javascript, which is think is easier to read in this situation:

var items = [];
function setUp()
{
    items = [];  // clear in case this gets recalled.
    $('.checkStatus').each(function(idx, el){
         values.push({variationID:$(el).data('id'), orderID:$(el).attr('id')});
    }
    if (items.length > 0)
    {
        consume();
    }
}
function handleResponse(data)
{
    // do your data handling and formatting here.
    if (items.length >= 0) consume();
}
function consume()
{
    var thisOrder = items.pop();
    $.ajax({
        url:jsonURL, 
        dataType:'jsonp', 
        data:{orderID:thisOrder.orderID, variationID:thisOrder.variationID},
        async:false,
        success:handleResponse
    });
}
setUp();

Note that although these all sit in the global namespace a they stand, they can easily sit inside of a closure or function (ie, wrap the whole thing in a $(document).ready() ).

John Green
  • 13,241
  • 3
  • 29
  • 51
  • 1
    It is cross site. I'm not sure I follow your explanation of 2. If possible could you kindly provide an example? – Fraser Jun 05 '12 at 04:45
3

Two things two change for a quick fix:

  1. Use var before your variables to make them local instead of global. That way, you'll get new variable instances for each of your iterations. Always use var unless you really intend on polluting the global namespace:

        var thisVariationID = $(this).attr('data-id');
        var thisOrderID = $(this).attr('id');
    
  2. Use == to compare instead of = ;)

        if (data.response == 'success'){
    

Your code will most likely start working as intended after fixing these issues that you seem to have overlooked. But, if you're willing to go with a more drastic change, you could also make use of Deferreds.

To execute a bunch of fetches in parallel:

var fetches = $('.checkStatus').map(function () {
    var thisVariationID = $(this).attr('data-id'),
        thisOrderID = $(this).attr('id');

    return $.getJSON(/* blah blah */);
});

fetches = $.when.apply($, fetches);

fetches.done(function () {
    // all parallel fetches done
});

To serialize fetches:

var fetching = $.when();

$('.checkStatus').each(function () {
    var thisVariationID = $(this).attr('data-id'),
        thisOrderID = $(this).attr('id');

    fetching = fetching.pipe(function () {
        return $.getJSON(/* blah blah */);
    });
});

fetching.done(function () {
    // last fetch done
});

Overkill? Perhaps. But it's flexible, and sometimes may be worth the syntactic sugar of having code that literally reads "when my fetches are done".

(Note: The above implementation is an optimistic implementation for illustration purposes only. In a real implementation you should also handle failures.)

Ates Goral
  • 137,716
  • 26
  • 137
  • 190
0

You just have to desactivate the async mechanisms. Have a look here : https://stackoverflow.com/a/933718/1343096

Community
  • 1
  • 1
tibo
  • 5,326
  • 4
  • 37
  • 53
0

See my comment I dont know why it went there instead of answer. Here its made synchronous, so it waits for a response.

jQuery: Possible to wait for $.get to finish loading before continuing?

Community
  • 1
  • 1
Pasha Immortals
  • 829
  • 1
  • 7
  • 19