-1

I am trying to cycle through an array and with each value in the array, use $.getJSON to return some JSON and populate an HTML table with the return values.

I have been following this post, but seem not get this to work:

$.getJSON calls misbehaving inside a for loop

Here is my function:

$("#selectProviderTop").click(function() {
    var restURL = window.location.protocol + "//" + window.location.hostname + (window.location.port == "" ? "" : (":" + window.location.port)) + "/restGetProvider/";
    var selected = [];
    var providerKey;
    var providerID;
    var providerLegacyID;
    var providerName;
    var finalURL;
    var tr;

    // First, create an array from the User Provider Keys...
    var userProviderKeys = $("#hiddenUserProviderKeys").val();
    selected = userProviderKeys.split(",");
    console.log("selected: " + selected);

    var tableHTML = "";
    var focus = $("<div></div>"); // either match an existing element or create one: '<div />'

    var arrayLength = selected.length;
    for (var i = 0; i < arrayLength; i++) {
        (function(i) {
            console.log("i: " + i);

            providerKey = selected[i];
            console.log("providerKey: " + providerKey);
            // Get that provider and populate the table...
            finalURL = restURL + providerKey;
            console.log("finalURL: " + finalURL);
            focus.queue('apicalls', function(next) {
                $.getJSON(finalURL, function(jsonObject) {
                    tableHTML += "<tr>";
                    tableHTML += "<td><a href=\"#\" onclick='selectProvider(\"" + providerKey + "\")'>" + jsonObject["providerName"] + "</a></td>";
                    tableHTML += "<td>" + jsonObject["providerID"] + "</td>";
                    tableHTML += "<td>" + jsonObject["providerLegacyID"] + "</td>";
                    tableHTML += "</tr>";
                    console.log("tableHTML: " + tableHTML);
                    next();
                });
            });
        })(i);
    }

    // Replace table’s tbody html with tableHTML...
    console.log("final tableHTML: " + tableHTML);
    $("#tableProviderSelect tbody").html(tableHTML);

    $('#modalSelectProviderForPTP').modal('show');

});

The userProviderKeys value is 0be32d8057924e718a8b6b4186254756,2dc5f826601e4cc5a9a3424caea4115f

The code never makes the $.getJSON call it just completes the for loop.

How do I update this code to get the first value in the array, grab the JSON, create the HTML, and then cycle through the loop?

I have tried setTimeout but that didn't help me out.

If you have some ideas, could you update my existing code - I understand better when I see the code itself. Thanks.

Dan
  • 940
  • 2
  • 14
  • 42
  • You're using ajax, and ajax is asynchronous. See https://stackoverflow.com/q/23667086/215552 and https://stackoverflow.com/q/14220321/215552 – Heretic Monkey Feb 07 '18 at 20:02
  • It looks like you're missing a call to `focus.dequeue('apicalls')` – Sunshine Feb 07 '18 at 20:02
  • @sunshine Reading the docs, I think that calling the `next` function as OP has done is equivalent to call the `.dequeue` method. – David Knipe Feb 07 '18 at 21:05
  • You need the initial call to start processing through the queue. This is just what I am inferring from the SO answer that he references, where there is a call to `dequeue` at the end which isn't present in his snippet. – Sunshine Feb 08 '18 at 17:57
  • @Sunshine Interesting... But from that link it looks like you only need to explicitly call `.dequeue` once to get things started, as long as you call the `next` functions when necessary. I'll change my answer to take this into account. – David Knipe Feb 09 '18 at 21:31
  • Why not simply add one more step to the queue? – Kevin B Feb 09 '18 at 21:46
  • @KevinB Like in my answer? – David Knipe Feb 09 '18 at 21:57
  • @DavidKnipe yeah, but i'm more interested in why that approach wasn't taken. – Kevin B Feb 09 '18 at 22:04

1 Answers1

-1

I don't know why you're doing this using queues. But you are, so I'm not going to rewrite your code to do it some other way.

The last few lines need to be called after all the queued functions have run, which means they should be called asynchronously. (Yes, you could make the whole thing synchronous as Marcus Höglund suggested, but that's no way to write scalable applications in javascript.) You could do this by adding another function to the queue containing these lines. Like this:

$("#selectProviderTop").click(function() {
    var restURL = window.location.protocol + "//" + window.location.hostname + (window.location.port == "" ? "" : (":" + window.location.port)) + "/restGetProvider/";
    var selected = [];
    var providerKey;
    var providerID;
    var providerLegacyID;
    var providerName;
    var finalURL;
    var tr;

    // First, create an array from the User Provider Keys...
    var userProviderKeys = $("#hiddenUserProviderKeys").val();
    selected = userProviderKeys.split(",");
    console.log("selected: " + selected);

    var tableHTML = "";
    var focus = $("<div></div>"); // either match an existing element or create one: '<div />'

    var arrayLength = selected.length;
    for (var i = 0; i < arrayLength; i++) {
        (function(i) {
            console.log("i: " + i);

            providerKey = selected[i];
            console.log("providerKey: " + providerKey);
            // Get that provider and populate the table...
            finalURL = restURL + providerKey;
            console.log("finalURL: " + finalURL);
            focus.queue('apicalls', function(next) {
                $.getJSON(finalURL, function(jsonObject) {
                    tableHTML += "<tr>";
                    tableHTML += "<td><a href=\"#\" onclick='selectProvider(\"" + providerKey + "\")'>" + jsonObject["providerName"] + "</a></td>";
                    tableHTML += "<td>" + jsonObject["providerID"] + "</td>";
                    tableHTML += "<td>" + jsonObject["providerLegacyID"] + "</td>";
                    tableHTML += "</tr>";
                    console.log("tableHTML: " + tableHTML);
                    next();
                });
            });
        })(i);
    }

    focus.queue('apicalls', function(next) {
        // Replace table’s tbody html with tableHTML...
        console.log("final tableHTML: " + tableHTML);
        $("#tableProviderSelect tbody").html(tableHTML);

        $('#modalSelectProviderForPTP').modal('show');

        next();
    });
});

Edit: Sunshine has pointed out that the linked stackoverflow post has mysterious references to the .dequeue method. In the accepted answer, this method is called explicitly after the tasks have been queued. I don't know whether this was necessary or not. I had thought that the problem was that the $.json bit wasn't happening until after the $("#tableProviderSelect tbody").html(tableHTML); part. But now I realise you wrote: "The code never makes the $.getJSON call it just completes the for loop." In that caseSunshine may have been right, and you need to add focus.dequeue('apicalls'); just after the last focus.queue(...);.

David Knipe
  • 3,417
  • 1
  • 19
  • 19