-1

I am making a 'viewer' for Twitch TV, which shows if TV channels are online,offline or don't exist. I am using the API for Twitch TV. I have saved the channel names in an array, but when I try to append an array item to an HTML element, it shows 'undefined'. The array is a global variable.

My code is in this fiddle.

HTML:

<div class="container-fluid">

<div class="row row-centered">

<div class="col-md-4"></div>  
<!-- This is a div containing divs for each channel --> 
<div class="col-md-4 col-centered" id="displayHere">


</div>
<!-- The container div end here -->
<div class="col-md-4"></div>  

</div>  

</div>

My Javascript:

$(document).ready(function(){
streamsArr=  ["ESl_SC2","OgamingSC2","cretetion","freecodecamp","storbeck","habathcx","RobotCaleb","noobs2ninjas","brunofin","comster404"];

 for(var count=0;count<streamsArr.length;count++){
 $.getJSON("https://api.twitch.tv/kraken/streams/"+streamsArr[count]+"?callback=?",function(data){

  if(JSON.stringify(data.stream)=="null")
   {
       $("#displayHere").append("<div style=\"padding:1%;\"><span style=\"font-size:1.3em;\"> "+streamsArr[count]+"</span><span style=\"color:red;\">OFFLINE</span></div>");//shows 'undefined'
    }
  else if(data.hasOwnProperty("error"))
    {
      $("#displayHere").append("<div style=\"padding:1%;\"><span style=\"font-size:1.3em;\"> "+streamsArr[count]+"</span><span style=\"color:red;\">UNAVAILABLE</span></div>");//shows 'undefined'
    }
  else{
  $("#displayHere").append("<div style=\"padding:1%;\"><span style=\"font-size:1.3em;\"> "+JSON.stringify(data.stream.channel.display_name)+"</span>"+JSON.stringify(data.stream.game)+"</div>");
  }
}); 
 } 
});

Can someone tell me where the fault lies? Thanks.

aks
  • 480
  • 7
  • 14
  • Possible duplicate of [jQuery / Ajax - $.ajax() Passing Parameters to Callback - Good Pattern to Use?](http://stackoverflow.com/questions/1194104/jquery-ajax-ajax-passing-parameters-to-callback-good-pattern-to-use) – Kira Aug 21 '16 at 06:18

3 Answers3

1

You have created a closure for the variable count since JavaScript has function scope, which is why the value of your count variable is always 10. With ES6, you can use let instead of var in the for loop so count will be block scoped.

jisoo shin
  • 540
  • 6
  • 15
  • Thanks! That worked in Firefox and Chrome, but not in Microsoft Edge and Internet Explorer. – aks Aug 21 '16 at 06:59
1

$.getJSON method is asynchronous so For loop may complete before current request returns a result. So value of the variable count becomes 10.

Here is a fiddle that works https://jsfiddle.net/bkw5dLac/1/

$(document).ready(function(){
streamsArr=  ["ESl_SC2","OgamingSC2","cretetion","freecodecamp","storbeck","habathcx","RobotCaleb","noobs2ninjas","brunofin","comster404"];

 for(var count=0;count<streamsArr.length;count++){ 
 getJSON(streamsArr[count]);
 } 
});

function getJSON(arr){
$.getJSON("https://api.twitch.tv/kraken/streams/"+arr+"?callback=?",function(data){
  if(JSON.stringify(data.stream)=="null")
   {
       $("#displayHere").append("<div style=\"padding:1%;\"><span style=\"font-size:1.3em;\"> "+arr+"</span><span style=\"color:red;\">OFFLINE</span></div>");//shows 'undefined'
    }
  else if(data.hasOwnProperty("error"))
    {
      $("#displayHere").append("<div style=\"padding:1%;\"><span style=\"font-size:1.3em;\"> "+arr+"</span><span style=\"color:red;\">UNAVAILABLE</span></div>");//shows 'undefined'
    }
  else{
  $("#displayHere").append("<div style=\"padding:1%;\"><span style=\"font-size:1.3em;\"> "+JSON.stringify(data.stream.channel.display_name)+"</span>"+JSON.stringify(data.stream.game)+"</div>");
  }
});
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container-fluid">

<div class="row row-centered">

<div class="col-md-4"></div>  
<!-- This is a div containing divs for each channel --> 
<div class="col-md-4 col-centered" id="displayHere">


</div>
<!-- The container div end here -->
<div class="col-md-4"></div>  

</div>  

</div>

Why OP's code not working as expected

1) Variable count is a global variable to the anonymous callback function in $.getJSON

2) $.getJSON is asynchronous. So anonymous callback function is triggered only after the success of get request.

3) When the anonymous callback executes, value of count will be modified in for loop. In many cases, it becomes 10. Because for loop completes execution before the callback is triggered

Why my fiddle is working

1) I have passed the value of streamArr at count to a local variable arr.

2) Since, arr is local variable to the function getJSON, its value will not be modified in for loop. So anonymous callback function works as expected.

Kira
  • 1,403
  • 1
  • 17
  • 46
  • Thanks! That worked perfectly. However, can you shed more light on why your code works while mine didn't? The only difference between your and my code, is that I had directly nested the getJSON within the for loop, while you included a callback inside the for loop. – aks Aug 21 '16 at 07:19
0

Let's try cleaning up the $.getJSON function up a bit first:

var twitchAPI = "https://api.twitch.tv/kraken/streams/"+streamsArr[count]+"?callback=?"

and then encapsulate the success callback in a closure that has the index bound to it:

$.getJSON(twitchAPI, function(count) {
    return function(data) {
        if (JSON.stringify(data.stream) == "null") {
            $("#displayHere").append("<div style=\"padding:1%;\"><span style=\"font-size:1.3em;\"> " + streamsArr[count] + "</span><span style=\"color:red;\">OFFLINE</span></div>");
        } else if (data.hasOwnProperty("error")) {
            $("#displayHere").append("<div style=\"padding:1%;\"><span style=\"font-size:1.3em;\"> " + streamsArr[count] + "</span><span style=\"color:red;\">UNAVAILABLE</span></div>");
        } else {
            $("#displayHere").append("<div style=\"padding:1%;\"><span style=\"font-size:1.3em;\"> " + JSON.stringify(data.stream.channel.display_name) + "</span>" + JSON.stringify(data.stream.game) + "</div>");
        }
    }
}(count));
Xenyal
  • 2,136
  • 2
  • 24
  • 51
  • Thanks for your help. Does this code work because you have passed the 'count' variable as a parameter, while I didn't? Also, what's confusing is that how does the getJSON function work at all when the JSON object 'data' is not passed as a parameter like $.getJSON(url,function(data){}); – aks Aug 21 '16 at 07:33