0

It looks like my for loop is looping the last object parsed into all fields.

http://codepen.io/anon/pen/EKxNaN

This is the actual code I am using, I built something kind of similar for codepen since I cannot request JSON from the actual source on codepen.

var championMasteryPHP = "https://api.myjson.com/bins/xked";

$.getJSON(championMasteryPHP, function (json) {
    for (var i = 0; i < json.length; i++) {
        var champID = json[i].championId;
        var champLevel = json[i].championLevel;
        var pointstonextlevel = json[i].championPointsUntilNextLevel;
        var championInfo = "http://example.com/champInfo.php?champid=" + champID;

        $.getJSON(championInfo, function (json2) {
            var champName = json2.name;
            var champTitle = json2.title;
            $('#champ').append("<li>ID: " + champID + " | Name: " + champName + " | Level: " + champLevel + " | Points to Next Level: " + pointstonextlevel + "</li>");
        });
    };
});

Long story short, what I am trying to achieve would look like this.

image0

But for some reason, this is what I get instead.

image1

The right names, but the other variables are the very last variable in the listing.

Is there a better way to do this? Am I doing something terribly wrong?

Thanks.

Tuan Ha
  • 620
  • 2
  • 8
  • 25
Zlkva
  • 39
  • 6
  • 2
    I'm pretty sure the problem is you have an async function inside a for loop, and when the async function is called they all reference the same index value. http://stackoverflow.com/questions/11488014/asynchronous-process-inside-a-javascript-for-loop – Eric Guan Feb 27 '16 at 05:05
  • Possible duplicate http://stackoverflow.com/questions/11488014/asynchronous-process-inside-a-javascript-for-loop – Jagdish Idhate Feb 27 '16 at 05:05
  • This is a `infamous loop problem`. Let me post my answer – Rajshekar Reddy Feb 27 '16 at 05:12
  • I don't think it is a good practice to make multiple AJAX (JSON) requests in a loop. Is there a way to build the complex object (containing data for both JSONs) server side, and get it with one request? – KostaShah Feb 27 '16 at 05:47

2 Answers2

2

You are using Asynchronous Process inside a javascript for loop more info here

You can modify to use self executing function, so it will work

var championMastery = "https://api.myjson.com/bins/xked";
$.getJSON(championMastery, function (json) {
for (var i = 0; i < json.length; i++) {

    (function(obj){
        var champID = obj.championId;
        var champLevel = obj.championLevel;
        var pointstonextlevel = obj.championPointsUntilNextLevel;
        var championInfo = "http://example.com/champInfo.php?champid=" + champID;

            $.getJSON(championInfo, function (json2) {
                var champName = json2.name;
                var champTitle = json2.title;
                $('#champ').append("<li>ID: "+champID+" | Name: " +champName+ " | Level: " +champLevel+ " | Points to Next Level: " +pointstonextlevel+ "</li>");
            });
    })(json[i])
};
});
Community
  • 1
  • 1
Jagdish Idhate
  • 7,513
  • 9
  • 35
  • 51
  • Beautiful! This seemed to fix the problem. Quick question though, Do you know why the append is out of order now when it is displayed on the page? http://i.imgur.com/4X8K5Rt.png – Zlkva Feb 28 '16 at 01:03
  • `$.getJSON` is Asynchronous function so `$('#champ').append` will depend on the response of server. You can also check [async](https://github.com/caolan/async) library to ease out the problem – Jagdish Idhate Feb 28 '16 at 02:32
1

A very good article which I came across recently. Detailing about the Javascript Scope ans Closures . This is a must know things for coding in javascript, Jquery. And the part where there is an explanation to this above problem is look for the topic under The Infamous Loop Problem

Now coming to the problem. Your code should actually look like

    $.getJSON(championInfo, function (json2) {
            (function(){
              var champName = json2.name;
              var champTitle = json2.title;
              $('#champ').append("<li>ID: "+champID+" | Name: " +champName+ " | Level: " +champLevel+ " | Points to Next Level: " +pointstonextlevel+ "</li>");            
            })()
            });

Note the change where I have added the self executing function. The problem you got the weird output with the same outputs for all the function is because.

  • Your function Inside the $.getJSON call back is just a function definition and the function is not executed at that moment. By the time your first getJSON hits its call back your for loop is complete, And the final value in the variables are of the last loop and hence when your first getJSONhits its callback it displays the values of the last loop.

To make it more simple. Write this in your console window.

function alert1(){ alert("I am one!!");}

And now call / execute the function by doing

alert1();

You will get a alert saying "I am one!!"

Now add this to the console

function alert1(){ alert("I am one, But overritten!!");}

And then try out calling it. The out put would be "I am one, But overritten!!", So the function actually gets overwritten and that's what is happening in the for loop. The last function is the one which is available for all the callbacks.

Rajshekar Reddy
  • 18,647
  • 3
  • 40
  • 59