Could someone tell me why my console.log is returning the same output for every loop and how to fix it? The console.log should be returning each element of the 'channels' array, but it keeps outputting the last element 'noobs2ninjas'.
It is a similar function to the FCC Twitch app here. The difference is that I swapped the .$getJSON order. Their app is getting the 'stream' first while I'm getting the 'channel' first. I've been comparing my code and theirs and could not understand why the inner .$getJSON will be repeating the same array element over and over again but the outter .$getJSON is looping through each element correctly.
function loadChannel() {
var channels = ["ESL_SC2", "OgamingSC2", "cretetion", "freecodecamp", "storbeck", "habathcx", "RobotCaleb", "noobs2ninjas"];
var display_name = null;
var logo = null;
var url = null;
var game = null;
var status = null;
var online = false;
function api(type, channel) {
return `https://api.twitch.tv/kraken/${type}/${channel}?callback=?`;
}
for (var index in channels) {
$.getJSON(api('channels', channels[index]), function(data) {
display_name = data.display_name;
logo = data.logo;
url = data.url;
game = data.game;
status = data.status;
$.getJSON(api('streams', channels[index]), function(data) {
// get online status
console.log(channels[index]); // <-- outputs same channel 'noobs2ninjas' each loop
console.log(data); // <-- outputs same object each loop
});
});
}
}
It's because var
in Javascript is function scoped, not block scoped; your var index
declaration is being hoisted to the the top of loadChannels and is overwritten each loop. This means that your async functions are only accessing the last index, since the loop finishes before the ajax calls do. There is a nice solution that you are pretty close to already though.
Using your existing code you could switch out just the for loop and instead utilize Array.forEach
. You will pass it a function that will create a new scope with the channel scoped locally to the loop (and therefore not overwritten on each iteration).
function loadChannel() {
var channels = ["ESL_SC2", "OgamingSC2", "cretetion", "freecodecamp", "storbeck", "habathcx", "RobotCaleb", "noobs2ninjas"];
var display_name = null;
var logo = null;
var url = null;
var game = null;
var status = null;
var online = false;
function api(type, channel) {
return `https://api.twitch.tv/kraken/${type}/${channel}?callback=?`;
}
channels.forEach(function (channel) {
$.getJSON(api('channels', channel), function(data) {
display_name = data.display_name;
logo = data.logo;
url = data.url;
game = data.game;
status = data.status;
$.getJSON(api('streams', channel), function(data) {
// get online status
console.log(channel); // <-- should be fixed
console.log(data); // <-- outputs same object each loop
});
});
});
}
It might also be wise to move the declaration of any other variables you plan to use inside the loop (display_name, logo, etc) into the forEach we just made.
References: