1

I'm making a website for my battlefield 1 clan, on this website i would like to display every player in this clan and also some of their in-game stats. The player list is stored in a database and i will get the stats from this api . This means that i will first get the player list from the database using ajax and then loop through them to get the player stats through a second ajax call in that loop.

It all sounds fun and games till i run my code, sometimes not all of the requests succeed and whenever i'm trying to display a displayname it will always show the one from the last call.

This is my code:

$(document).ready(function() {
  $.ajax({
    url: 'playerlist.php',
    method: 'POST',
    data: {
      playercheck: 1,
    },
    success: function(response) {
      var len = response.length;
      for (var i = 0; i < len; i++) {
        var psnid = response[i].psnid;

        // second ajax 

        var request = new XMLHttpRequest();

        request.open('GET', 'https://battlefieldtracker.com/bf1/api/Stats/BasicStats?platform=2&displayName=' + psnid);

        request.setRequestHeader('TRN-Api-Key', '125a7cbe-1bbe-45d4-9f70-3aa838fc7535');

        request.onreadystatechange = function() {
          if (this.readyState === 4 && this.status == 200) {
            console.log('Status:', this.status);
            console.log('Headers:', this.getAllResponseHeaders());
            console.log('Body:', this.responseText);
            var result = JSON.parse(request.responseText);

            console.log(result);
            $("#userTable").append(result['profile']['displayName']);
          }
        };

        request.send();

        // end second

      }
    },
    dataType: "json"
  });
});

If you guys could tell me what is causing this and help me find a solution, that would be great. Thanks in advance!

CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
Dennishofken
  • 317
  • 2
  • 9
  • Possible duplicate of [JavaScript closure inside loops – simple practical example](https://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example) – Draco18s no longer trusts SE Apr 22 '18 at 20:26

2 Answers2

1

This is most likely a variable scope issue. In JavaScript, a variable declaration with var is "hoisted" to the top of the containing function. Also, the scope of the variable is the function, NOT the for loop.

So while it looks as if every for loop iteration ought to be creating a completely separate request, instance, that is not what is happening. And by the time the onreadystatechange event fires, your request value has probably changed.

There are two ways to solve this. First, using the new let or const variable declarations of es6 JS, the scope is different. So if you don't need this to work in older browsers, you can just change from var request to let request, and it should work.

If this isn't possible, you'll need to come up with a way to limit the "scope" of your request variable, such as putting your request code in a function, and then calling the function from inside your for loop.

David784
  • 7,031
  • 2
  • 22
  • 29
0

Try this refactorized version:

$(document).ready(function() {
  $.ajax({
    url: "playerlist.php",
    method: "POST",
    data: {
      playercheck: 1
    },
    success: function(response) {
      getStats(response);
    },
    dataType: "json"
  });
});

function getStats(stats) {
  var len = stats.length;
  for (var i = 0; i < len; i++) {
    getStatInfo(stats[i].psnid);
  }
}

function getStatInfo(psnid) {
  var request = new XMLHttpRequest();

  request.open(
    "GET",
    "https://battlefieldtracker.com/bf1/api/Stats/BasicStats?platform=2&displayName=" +
      psnid
  );

  request.setRequestHeader(
    "TRN-Api-Key",
    "125a7cbe-1bbe-45d4-9f70-3aa838fc7535"
  );

  request.onreadystatechange = function() {
    if (this.readyState === 4 && this.status == 200) {
      console.log("Status:", this.status);
      console.log("Headers:", this.getAllResponseHeaders());
      console.log("Body:", this.responseText);
      var result = JSON.parse(request.responseText);

      console.log(result);
      $("#userTable").append(result["profile"]["displayName"]);
    }
  };

  request.send();
}
amedina
  • 2,838
  • 3
  • 19
  • 40
  • Just like the first answer, this solution works like a charm. But could you elaborate what changes you made for which reason? – Dennishofken Apr 22 '18 at 20:32
  • @CheapGamer Because of the scope of the `request` variable (`request` variable was being overwritten) and because I found it easier to start refactoring the code so I could understand its parts better :). – amedina Apr 22 '18 at 20:34