3

I have created a for loop that loops the number of times that an element appears in a container. The for loop grabs some data from the HTML and creates a JSON url which will then return a value. That value should then be added to the HTML in the appropriate place.

The problem seems that the for loop completes before all of the Ajax calls are made, so only the last value is being added to the HTML. I thought that I could make sure that the readystate is equal to 4, but that solution did not work. I also tried using complete, rather than success as an Ajax Event. Any insights? Here is my the code.

for(var index = 0; index < $('#wizSteps #step6 label').length; index++){
    var priceCount;
    console.log(index);
    var currentSelect = $('#wizSteps #step6 label[data-pricepos="'+index+'"]');
    url = 'http://www.thesite.com/api/search.json?taxonomy=cat3435' + currentSelect.find('input').attr('name');
    jQuery.ajax({
        url: url,
        dataType: "JSON",
        success: function( data ){
            var totalResult = data.totalNumberOfResults;
            console.log(currentSelect);
            currentSelect.find('.itemCount').text(totalResult);

        }     
    });
}
6
  • Ajax is asynchronous. You are starting them in order, but they will complete at a later time, possibly in a different order. Commented Jan 20, 2014 at 18:10
  • 4
    Regarding currentSelect: Javascript closure inside loops - simple practical example Commented Jan 20, 2014 at 18:11
  • have you tried adding async: false, to your AJAX options right before url: url,? Commented Jan 20, 2014 at 18:20
  • @MonkeyZeus I don't know if he has, but I know he shouldn't. Commented Jan 20, 2014 at 18:20
  • 1
    async: false will surely solve the problem, but it will lock the browser up during the request, making your page look broken. Do not use async: false in this case. Commented Jan 20, 2014 at 18:21

4 Answers 4

2

It looks like you don't necessarily need the requests to finish in order, you just need to keep track of currentSelect in a way that works. For that, you can use the context ajax option:

for (var index = 0; index < $('#wizSteps #step6 label').length; index++) {
    var currentSelect = $('#wizSteps #step6 label[data-pricepos="' + index + '"]');
    url = 'http://www.thesite.com/api/search.json?taxonomy=cat3435' + currentSelect.find('input').attr('name');
    jQuery.ajax({
        url: url,
        dataType: "JSON",
        context: currentSelect,
        success: function (data) {
            var totalResult = data.totalNumberOfResults;
            this.find('.itemCount').text(totalResult);

        }
    });
}
Sign up to request clarification or add additional context in comments.

Comments

2

That is ok, the calls are not supposed to be done this way. They are only initiated in the loop.

Ajax is asynchronous. The queries are completed later, may be in different order.

If you want to be sure that every call is completed before you do the next one, you must integrate the next call into the callback function of the previous.

In your case the variable may be overwritten in the call back function. You can learn more on this here:

Another interesting question/discussion related to the topic:

It does not directly answer your question, but helps to understand the problem deeper. The point is that you probable don't need the loop at all (or you do but in a completely different form).

5 Comments

How is that ok? The results are incorrect, according to the beginning of the second paragraph in the question.
It's ok because that's the expected behavior of the given code. Whether or not that's the intended behavior is another story.
@KevinB: Um.... Isn't that the point of StackOverflow? To get code that doesn't do what is intended to perform the work that is intended?
Sure, but this answer does explain why it is happening, code isn't always required. The updated answer does at least give a suggestion of how to fix it.
Yeah, that's better. :)
0

You should try creating a recursive function, that you will call again in the success of the ajax call, this way you will be sure that the next ajax call will be called only once the previous call is done.

Comments

0

If you want the requests in a sequence, you can work with a queue.

First build the queue:

var queue = [],
    index,
    stepLength = $('#wizSteps #step6 label').length;

for(index = 0; index < length; index++){
    var priceCount;
    console.log(index);
    var currentSelect = $('#wizSteps #step6 label[data-pricepos="'+index+'"]');
    url = 'http://www.thesite.com/api/search.json?taxonomy=cat3435' + currentSelect.find('input').attr('name');
    queue.push([url, currentSelect]);
}

And after that do the serial ajax requests:

function serialAjax() {
    if(queue.length === 0) {
        return;
    }
    var queueData = queue.shift(),
        url = queueData[0],
        currentSelect = queueData[1];

    jQuery.ajax({
        url: url,
        dataType: "JSON",
        success: function( data ){
            var totalResult = data.totalNumberOfResults;
            console.log(currentSelect);
            currentSelect.find('.itemCount').text(totalResult);
            serialAjax();
        }     
    });
};
// call the function
serialAjax();

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.