bademeister bademeister - 7 months ago 36
Javascript Question

Next iteration of $.each when received AJAX-content

The question has been asked before, but it is almost four years ago and maybe there is a better solution.

I have a $.each-loop where sometimes additional data is being fetched via ajax.

I am bulding an object with the fetched data, after the loop there is a function that generates HTML from the object. The problem is that the loop finishes before the ajax data arrives. If I place an alert in the HTML-generating-function the content is loading properly.

I am searching for a solution that calls the HTML-generator-function only when the loop and all ajax calls are finished. Maybe it is a solution to count the started Ajax requests and wait if all of them are finished?

I believe jQuery deferred is the right solution for me but I do find only examples where everything stays inside the loop. Can someone help?

I have stripped down my code to the most important things:

//goes through each testplace -->main loop
$.each(jsobject, function(key, value)
{
//build object together...
for (var i = 0, numComputer = jenkinsComputer.contents.computer.length; i < numComputer; i++)
{
//If the testplace is in both objects then fire AJAX request
if (jenkinsComputer.contents.computer[i].displayName == key) //<<<This can happen only once per $.each loop, but it does not happen every time
{
//next $.each-iteration should only happen when received the JSON
var testplaceurl = jenkinsComputer.contents.computer[i].executors[0].currentExecutable.url;
$.when($.getJSON("php/ba-simple-proxy.php?url=" + encodeURI(testplaceurl) + "api/json?depth=1&pretty=1")).done(function(jenkinsUser)
{
//build object together...
});
}
}

}); //End of main Loop ($.each)
generateHTML(builtObject);


It would be great if someone could give me an advice how to do it.

Answer

I would do something like this:

var thingstodo = $(jsobject).length;
var notfired = true;
$.each(jsobject, function(key, value)
{
 //build object together...
  for (var i = 0, numComputer = jenkinsComputer.contents.computer.length; i < numComputer; i++)
  {
    //If the testplace is in both objects then fire AJAX request
    if (jenkinsComputer.contents.computer[i].displayName == key) //<<<This can happen only once per $.each loop, but it does not happen every time
    {
      //next $.each-iteration should only happen when received the JSON
      var testplaceurl = jenkinsComputer.contents.computer[i].executors[0].currentExecutable.url;
      $.when($.getJSON("php/ba-simple-proxy.php?url=" + encodeURI(testplaceurl) + "api/json?depth=1&pretty=1")).done(function(jenkinsUser) 
      {
        //build object together...
        thingstodo--;
        if(thingstodo === 0 && notfired){
            notfired = false;
            generateHTML(buildObject);
        }
      });
    }else{
        thingstodo--;
    }
  }

}); //End of main Loop ($.each)
if(thingstodo === 0 && notfired){
    generateHTML(buildObject);
}