-1

I'm trying to check if the twitch stream is online or offline and if so change a background colour. If i check without the array and just put in the name it works, but with the array it doesn't (I don't have a lot of knowledge of JSON).

function test() {
  var twitchChannels = ["imaqtpie", "summit1g", "tyler1", "greekgodx"];

  for (var i = 0; i < twitchChannels.length; i++) {
    console.log(i + " " + twitchChannels[i]);

    $.getJSON('https://api.twitch.tv/kraken/streams/' + twitchChannels[i] + '?client_id=XXXX', function(channel) {
      console.log(i + " " + twitchChannels[i]);

      if (channel["stream"] == null) {
        console.log("Offline: " + twitchChannels[i])
        document.getElementById(twitchChannels[i]).style.backgroundColor = "red";
      } else {
        console.log("Online: " + twitchChannels[i])
        document.getElementById(twitchChannels[i]).style.backgroundColor = "green";
      }

    });
  }

}

Error: http://prntscr.com/i6qj51 inside the red part is what happens inside of json fuction

Angel Politis
  • 10,955
  • 14
  • 48
  • 66
Pretpacked
  • 31
  • 1
  • 6
  • 1
    Possible duplicate of [passing index from for loop to ajax callback function (JavaScript)](https://stackoverflow.com/questions/6077357/passing-index-from-for-loop-to-ajax-callback-function-javascript) – t.niese Jan 28 '18 at 15:29
  • `$.getJSON` is async, as of that the value of `i` in your callback won't be what you expect that it would be. Either use `let i` or the method descriped in the duplicate. – t.niese Jan 28 '18 at 15:30
  • See also [JavaScript closure inside loops – simple practical example](https://stackoverflow.com/questions/750486) and [How do JavaScript closures work?](https://stackoverflow.com/questions/111102/how-do-javascript-closures-work?rq=1) – t.niese Jan 28 '18 at 15:34

4 Answers4

0

Your code is quite weak since you didn't manage the callback of every get you make. Also you didn't check if:

document.getElementById(twitchChannels[i])

is null, since the exception clearly stated that you can't get :

.style.backgroundColor

from nothing.

Basic check VanillaJS:

if(!document.getElementById("s"))
  console.log('id ' + twitchChannels[i] +  ' not found in dom')
else 
  console.log('id ' + twitchChannels[i] +  ' found in dom')

Also consider mixing JQuery with VanillaJS extremely bad practice; use proper JQuery method to access dom element by ID .

Black.Jack
  • 1,878
  • 2
  • 22
  • 39
  • Your answer does not contain any ingformation how the problem can be solved. – t.niese Jan 28 '18 at 15:36
  • add logic to test dom VanillaJS – Black.Jack Jan 28 '18 at 15:38
  • _"mixing JQuery with VanillaJS extremely bad practice"_ : It's not bad practice at all, if you know what you are doing. – Angel Politis Jan 28 '18 at 15:42
  • In the given code `document.getElementById(twitchChannels[i])` will always return `null`. The test if `document.getElementById(twitchChannels[i])` is `null` is good practice, but it does not solve the problem. – t.niese Jan 28 '18 at 15:43
  • @AngelPolitis: well it's arguable. For my experience in big project that should be cause of great problems. Especially on long term ones. t.niese: https://jsfiddle.net/Black_Jack/LsL3pmLm/1/ – Black.Jack Jan 28 '18 at 15:48
0

You should pass twitchChannel to the function because the var i is changing, this is an issue like others already mentioned: Preserving variables inside async calls called in a loop.

rokdd
  • 541
  • 4
  • 14
  • 1
    The test in the loop is _less then_(`<`) and not _less or equal then_ (`<=`), so `twitchChannels.length-1` would be wrong. – t.niese Jan 28 '18 at 15:40
0

The problem is that you made some ajax call in a cicle, but the ajax calls are async.

Whey you get the first response, the cicle is already completed, and i==4, that is outside the twitchChannels size: that's why you get "4 undefined" on your console.

You can change your code in such way:

function test() {
    var twitchChannels = ["imaqtpie", "summit1g", "tyler1", "greekgodx"];

    for (var i = 0; i < twitchChannels.length; i++) {
        executeAjaxCall(twitchChannels[i]);
    }
}
function executeAjaxCall(twitchChannel){
    $.getJSON('https://api.twitch.tv/kraken/streams/' + twitchChannel + '?client_id=XXXX', function(channel) {
        console.log(twitchChannel);

        if (channel["stream"] == null) {
            console.log("Offline: " + twitchChannel)
            $('#'+twitchChannel).css("background-color", "red");
        } else {
            console.log("Online: " + twitchChannel)
            $('#'+twitchChannel).css("background-color", "green");
        }

    });
    }
}
debe
  • 1,752
  • 2
  • 12
  • 11
0

When console.log(i + " " + twitchChannels[i]); is called inside the callback function, the variable i has already been set to 4, and accessing the 4th element of array twitchChannels gives undefined since the array has only 4 elements.

This is because $.getJSON is a shorthand Ajax function which, as the name suggests, executes your requests asynchronously. So what actually happened is, based on the output you provided,

  1. The loop is executed 4 times, and four Ajax requests have been sent.
  2. The loop exits; i is already set to 4 now.
  3. The ajax requests return; the callbacks are called, but the i value they see is now 4.

You can change the console.log inside your callback to something like console.log(i + " " + twitchChannels[i] + " (inside callback)"); to see this more clearly.

The correct result can be obtained by binding the current value of i to the closure.

function test() {
  var twitchChannels = ["imaqtpie", "summit1g", "tyler1", "greekgodx"];

  function make_callback(index) {
    return function (channel) {
        console.log(index + " " + twitchChannels[index]);

        if (channel["stream"] == null) {
          console.log("Offline: " + twitchChannels[index])
          document.getElementById(twitchChannels[index]).style.backgroundColor = "red";
        } else {
          console.log("Online: " + twitchChannels[index])
          document.getElementById(twitchChannels[index]).style.backgroundColor = "green";
        }
    }
  }

  for (var i = 0; i < twitchChannels.length; i++) {
    console.log(i + " " + twitchChannels[i]);

    $.getJSON('https://api.twitch.tv/kraken/streams/' + twitchChannels[i] + '?client_id=XXXX', make_callback(i));
  }

}
Tony Beta Lambda
  • 529
  • 3
  • 18