Javascript object error in viewer

I’m missing something that’s probably super-obvious in my JSON API project.

Here’s my pen:

The issue is with the Javascript object in which I’m attempting to store all the stream data responses from Twitch. When I send it to the console, I can see that the data for each stream is present. However, when I try to access the information within the object in my Javascript, I get “undefined.” I also only see a series of empty objects keyed to the Twitch usernames when I print the object in a div on the page.

Here’s the code that I think is relevant:

var userArray = ["ESL_SC2", "OgamingSC2", "cretetion", "freecodecamp", "storbeck", "habathcx", "RobotCaleb", "noobs2ninjas"]; //provided by FCC as active users
var userCount = userArray.length;
var streamResponses = {};

//loop through userArray, get stream data, and store it in streamResponses
for (i=0; i<userCount; i++) {
  currentUser = userArray[i];
  streamResponses[currentUser] = {};
  }; //end for

function getStreams(currentUser) {
  call = new URL("" + currentUser);
  $.getJSON(call, function(result) {
    streamResponses[currentUser] = result;
}; //end getStreams

When I call streamResponses in the console, I see this:

When I print out streamResponses into a random <div> in the document itself (as a test), I see this:

I’m certain I’m missing something that should be obvious, here. Who can help me become less ignorant about this?!

The getJSON function is asynchronous, so any code which can run while it is waiting for a response to come back, will continue to run. In your code, the following two lines are outside the getJSON callback function:

document.getElementById("status").innerHTML = JSON.stringify(streamResponses);

The for loop which calls the function containing the getJSON call finishes before the first response has time to come back. The following line creates the overall object:

streamResponses[currentUser] = {};

which is why you have an object with the usernames as properties, but nothing else shows inside. When working with asynchronous functions, you must rethink how you display data. In your case, you want to wait until all of the usernames API calls have finished.

How would you know when all responses have come back? Well, you have a users array of a specific length and you are creating an object with a specific number of properties. When the length of the users array is equal to the number of properties in the object, you know that all the responses are complete. You should already know how to get an array’s length and a call to Object.keys(streamResponses) will return an array of the properties in streamResponses. Then, you could compare the two arrays’ lengths inside the getJSON call and only display the data once the two lengths are equal.

1 Like

Thank you for your help! Your response got me on the right track, and after playing around with it for a while, I ended up implementing a solution after the &.get:

function waiterStreamResponses() { 
  if (streamResponses[userArray[userCount-1]].hasOwnProperty("stream")) {
    //what to do after page has called data & populated streamResponses
  } else {
    setTimeout(waiterStreamResponses, 30);
}; //end waiterStreamResponses

I found that comparing Object.keys(streamResponses).length to userCount didn’t work for me (which is due to me screwing something up in implementation, I’m sure), but telling the code to wait until after the last item in streamResponses was populated (by checking for a property I knew would be in the response) before doing the next thing worked swimmingly.

This was my first time dealing with asynchronous code, and it was kicking my butt. Thanks again for the assistance!