-3

I have the following code, which connects to an API through $.getJSON, takes the JSON, and then loops 3 times (Because it has 3 objects as data.length) through the for a loop. In each of these 3 iterations, it creates another $.getJSON to fetch specific new data with required parameters from the iteration of the first connection.

var baseAPI = "https://api.guildwars2.com/";
var versionAPI = ["v1", "v2"];
var endpointAPI = ["account", "guild_details.json", "guild", "stash", "items"];
var bearerAPI = ["access_token", "guild_id"];

$('#keyInput_user_FORM').on('submit', function(e) {
  e.preventDefault();
  var mordant = "https://api.guildwars2.com/v2/guild/927CDDD7-4E8D-E411-A8E7-AC162DAE5A05/stash?access_token=EDCD27E4-3A1B-3C44-9C5B-99F062596A9BB1C9C824-AE01-4F6F-9EA9-CBAD2D721C9D";
  $(".JuilsContainer").append('<div class="bankResult"></div>');

  $.getJSON( encodeURI(mordant), {
    tagmode: "any",
    format: "json"
  }).done(function( data ) {
    for(var bankCount = 0; bankCount < data.length; bankCount++){
      $(".bankResult").append('<div class="inventory" id="upgradeID_'+data[bankCount].upgrade_id+'"><header>'+data[bankCount].note+'</header><ul class="inventory_UL"></ul></div>');
      $.each( data[bankCount].inventory, function( i, inventory ){ /*can also run on property .size but running inventory guarantees not running more or less than there are items instead of slots.*/
        if(data[bankCount].inventory[i] != null){
          var accountAPI = baseAPI + versionAPI[1] + "/" + endpointAPI[4] + "/" + data[bankCount].inventory[i].id;
          $.getJSON( encodeURI(accountAPI), {
            tagmode: "any",
            //async: false,
            format: "json"
          }).done(function( item_data ) {
            $('#upgradeID_'+ data[bankCount].upgrade_id + ' .inventory_UL').append('<li class="bankInventory_item" id="item_'+item_data.id+'"><img src="'+encodeURI(item_data.icon)+'"><span class="itemCount">'+ data[0].inventory[i].count + '</span></li>');
          });
        }else{
          $('#upgradeID_'+ data[bankCount].upgrade_id + ' .inventory_UL').append('<li class="bankInventory_item" class="item_null"></li>');
        }
      });
    }
  });

});

Sadly all $.getJSON calls within the first loop are done after the 3 iterations are done, the loop is over. I want the second connection to take effect while inside the loop, not after it's done looping 3 times.

Furthermore, for some reason, it doesn't use the correct iteration var when it gets to all the second $.getJSON calls. Variable bankCount appears to be 3 while it could only get up to 2 since it has 3 objects its counting and looping through.

That happens on this line.

$('#upgradeID_'+ data[bankCount].upgrade_id + ' .inventory_UL').append('<li class="bankInventory_item" id="item_'+item_data.id+'"><img src="'+encodeURI(item_data.icon)+'"><span class="itemCount">'+ data[0].inventory[i].count + '</span></li>');

When it's trying to use data[bankCount].upgrade_id but bankCount appears to be 3 while there are only 3 objects (thus, it should max be 2, since there aren't anymore.)

All $.getJSON calls aren't executed right away. They are somehow queued up until all loops are done. Only when it's done looping 3 times from the first $.getJSON it executes and returns all from the ones queued up within the loop. ^ question edited, hopefully more clear

And how can variable bankCount turn 3 when there are only 3 objects (thus should be max 2).

xxx
  • 1,153
  • 1
  • 11
  • 23
Rien
  • 398
  • 2
  • 12
  • 37
  • You're asking two questions at the same time, but as for the `bankCount` issue, see http://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example. The second question I don't understand at all. – JJJ May 16 '16 at 15:02
  • "And how can variable bankCount turn 3 when there are only 3 objects (thus should be max 2)." because 2+1 equals 3, and when it is 3, the for loop stops. – Kevin B May 16 '16 at 15:04
  • @Juhana i've edited my post regarding the other problem – Rien May 16 '16 at 15:10
  • Leaving a reason why it's being downvoted would be nice.. – Rien May 16 '16 at 15:14
  • Your question(s) is a duplicate of http://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example – Kevin B May 16 '16 at 15:23

1 Answers1

0

Side point: I'm not sure why the code didn't do what you want when you set async to false. But, says I, that's not really an interesting case, because you really never want to do a synchronous ajax call -- it just leads to non-responsive web pages and generally poor user experience.

So, I'm going to translate your question into: "I want to loop over a set of objects; call $.getJSON asynchronously on each; and only start each call after the previous one has completed."

You can do this by making each call to $.getJSON from within the .done handler of the previous call.

If you always had exactly three elements in your data, then you could do this in a straightforward (but ugly) way by nesting the three call to $.getJSON.

But, I assume that your data can be of arbitrary length. This forces you to use a cleaner solution...

You will need to replace your for-loop iteration with recursive calls.

Something like the following:

...
submitHelper(data, 0);
...

function submitHelper(data, pos) {
  if (pos >= data.length) {
    return;
  }
  $.getJSON(..., done: function(itemData) {
    ...
    submitHelper(data, pos++);
    }
...
David Goldfarb
  • 1,796
  • 3
  • 18
  • 32
  • The problem I have with it being asynchronized, it creates elements in the order it finishes the ajax calls. Not in the order the data is supplied. – Rien May 16 '16 at 15:34
  • 1
    @KrijnvanderBurg the solution in this answer causes them to be received in the order data was supplied. downside is it only makes 1 request at a time, so it will be slower. – Kevin B May 16 '16 at 15:42
  • I really lost my way. I have no idea anymore how to actually apply above code to mine. Am trying as we speak – Rien May 16 '16 at 15:47
  • My apologies gentlemen but I have no idea how to apply above's code. – Rien May 16 '16 at 15:57