0

I was wondering what the issue with the bottom loop is or if I'm going through the last json wrong somehow when I'm trying to log it into the console. The arrays are above the given code and the first two loops work fine. I'm trying to return goals but the reality is I want to find an efficient way to return all of the stats.

     d3.json('https://statsapi.web.nhl.com/api/v1/teams', function(data) {
      for (i=0; i < 31; i++) {
          teamID.push(data.teams[i].id);
      }
  });

  console.log(teamID);

  // request roster json data from API and loop through roster to get all player IDS
  // and append them to the playerList array

  d3.json('https://statsapi.web.nhl.com/api/v1/teams/1/?expand=team.roster', function(data) {
      for (i=0; i < data.teams[0].roster.roster.length; i++) {
        playerList.push(data.teams[0].roster.roster[i].person.id);
      }
  });

  console.log(playerList);

  // request player stat json data from API and loop through all players to get all stat
  // and append them to an array

  var playerStats = [];

    for (i = 0; i < playerList.length; i++) {
        d3.json('https://statsapi.web.nhl.com/api/v1/people/' + playerList[i] + '/stats/?stats=statsSingleSeason&season=20172018', function(data) {
          console.log(data.stats[0].splits[0].stat.goals);
        });

  //      console.log(playerStats);
      };
Ralph B
  • 27
  • 5
  • 1
    You seem to be attempting to loop over data before it exists. – th3n3wguy Feb 12 '18 at 23:38
  • playerList[i] won't be defined if I move the loop under the request though – Ralph B Feb 12 '18 at 23:42
  • => I posted an answer. I am not 100% sure that it will be correct, but that is the best you will likely be able to do unless you use some Promise library to make the HTTP requests, which will make it much easier (such as Bluebird). – th3n3wguy Feb 12 '18 at 23:49

2 Answers2

1

Your final loop is probably attempting to initialize / run at the same time as the HTTP calls are being returned from the APIs. Since you are using callbacks to get the details, rather than promises, then you will need to do this in callback form. Here is the best I can do without you actually showing me the full code:

d3.json('https://statsapi.web.nhl.com/api/v1/teams', function(teamResponse) {
  var teamIds = teamResponse.teams.filter((team, i) => i < 31)
    .map((team) => team.id);

  // I use the functional approach above because I think it is cleaner than loops.
  // for (i=0; i < 31; i++) {
  //    teamID.push(data.teams[i].id);
  //}

  d3.json('https://statsapi.web.nhl.com/api/v1/teams/1/?expand=team.roster', function(rosterResponse) {
    var playerIdList = rosterResponse.teams[0].roster.roster
      .map((roster) => roster.person.id);

    // Swap this out for the functional method above.
    //for (i=0; i < data.teams[0].roster.roster.length; i++) {
    //  playerList.push(data.teams[0].roster.roster[i].person.id);
    //}

    for(var i = 0; i < playerIdList; i++) {
      d3.json('https://statsapi.web.nhl.com/api/v1/people/' + playerIdList[i] + '/stats/?stats=statsSingleSeason&season=20172018', function(data) {
        console.log(data.stats[0].splits[0].stat.goals);
      });
    }
  });
});
th3n3wguy
  • 3,649
  • 2
  • 23
  • 30
0

Promises (Promise.all) are not supported at all in Internet Explorer (they are in Edge) and some older versions of other browsers. Arrow functions are also not supported in these browsers.

I assume that when you need to support older browsers you can use babel (with webpack) or know how to write ES5.

d3.json returns a promise so you can leave out the callback and uses promises:

Promise.all([
  d3.json('https://statsapi.web.nhl.com/api/v1/teams'),
  d3.json('https://statsapi.web.nhl.com/api/v1/teams/1/?expand=team.roster')  
])
.then(
  ([teams,playerData])=>{
    const playerList = playerData.teams[0].roster.roster.map(
      player=>player.id
    );
    return Promise.all(
      playerList.map(
        playerID=>
          d3.json(`https://statsapi.web.nhl.com/api/v1/people/${playerID}/stats/?stats=statsSingleSeason&season=20172018`)
      )
    ).then(
      (playerStats)=>[teams,playerData,playerStats]
    )
  }
)
.then(
  ([teams,playerData,playerStats])=>{
    console.log("teams:",teams);
    console.log("playerData:",playerData);
    console.log("playerStats:",playerStats);
  }
)
.catch(
  err=>console.warn("Something went wrong:",err)
);

I did not comment on how the code works so please let me know if you have specific questions about the code. I suggest reading this if you don't know why promises are used. And google "mdn promise all" before asking what promise all does.

HMR
  • 37,593
  • 24
  • 91
  • 160
  • 1
    The only reason I didn't suggest this method is because the `Promise` object is not fully-supported in all browsers (especially with older versions of IE), which is why I write my code below the way I did. Now, if you don't have to support old browsers, this is the correct answer. – th3n3wguy Feb 14 '18 at 15:18
  • @th3n3wguy I think it's best to use standard promise syntax and try to polyfil Internet Explorer needs to be supported. I'll add a warning in the answer but assume most people would be aware of build tools and polyfils by now. – HMR Feb 14 '18 at 15:43
  • I agree, but I was showing a way to do it without having to worry about cross-browser implementations / polyfills, in case someone comes across this in the future. :) – th3n3wguy Feb 15 '18 at 20:22