"if" loop - set the text of an element

"if" loop - set the text of an element
0

#1

So I’m building this TwitchTV-something and I’m trying to set the value of a div: if “stream” is null - set to “offline”, if not - “online”. But I can’t find a way to set a different value of each element. “text” will make all elements with class “status” the same, “append” will just append words over and over… Is there something like adding an [i] after jQuery, so I can change the value of just this one element?

if (isStreaming === null) {
$(".status").text(“OFFLINE”);
} {
$(".status").text(“ONLINE”);
}

My codepen: https://codepen.io/Strzesia/pen/PJVjbR


#2

You can use [0] with a jQuery selector to get the DOM node list to which it refers, which you can then traverse like a normal node list (you can’t use jQuery methods on the elements, though, because DOM nodes aren’t jQuery objects).

$('.status')[0]; //a node list of elements with class `.status`
$('.status')[0][0]; //the first element of that node list
$('.status')[0][0].textContent = 'ONLINE'; //sets its text to 'ONLINE'
$('.status')[0][0].text('ONLINE'); //doesn't work because not a jQuery object
$($('.status')[0][0]).text('ONLINE'); //this would work, but it's a bit circuitous
//and ugly as hell...

The idiomatic jQuery way to do it is as follows:

$('.status').eq(0).text('ONLINE');

See https://api.jquery.com/eq/ .

With all that said… are you sure this is what you want to do? It’d probably be easier to set all this when you’re getting info from the API rather than post hoc.


#3

To add to that… I’ve only ever really used jQuery for manipulating DOM elements, not creating them, but I just found out that jQuery has a really sweet idiomatic way of building up elements before inserting them into the DOM:

Slightly modified version:

var myNewDiv = $('<div/>', {
   'id': 'foo',
   'name': 'mainDiv',
   'class': 'wrapper',
   'click': function() {
     $(this).toggleClass('test');
   }});
//then do whatever you want with myNewDiv

I’d suggest doing something similar with each of your returned bits of AJAX data. Then you can insert those newly-built elements however you like to get the desired effect.


#4

Ok i got this working in codepen so decided to post it … made a few changes

  1. created variable for your first url makes things handier
  2. in your second ajax request you were using url +name should be url + displayName … name is a html
  3. added a else to your if statement you forgot to add it
  4. changed var status = "<div class='col-4 status'></div>"; to var status = ‘’; … then put status = "<div class='col-4 status'>OFFLINE</div>" In your if statement and status =' "<div class='col-4 status'>ONLINE</div>"in your else
    and after that then it worked.
streamers = ["ESL_SC2", "OgamingSC2", "cretetion", "freecodecamp", "storbeck", "habathcx", "RobotCaleb", "noobs2ninjas"];

$(document).ready(function(){
  
  for (var i = 0; i <streamers.length; i++) {
   // CREATED VARIABLE FOR URL ...
    let url = "https://wind-bow.glitch.me/twitch-api/channels/" + streamers[i];
    console.log(url)
  debugger;
    $.ajax({
      
      url: url, //NOW STORED IN VARIABLE
      
      success: function (channelData) {
        console.log(channelData);
        var displayName = channelData.display_name;
        var profilePictureLink = channelData.logo;
                
        var profileLogo = "<div class='col-2 profileLogo'><img src='" + profilePictureLink + "'></div>";
        var name = "<div class='col-6'>" + displayName + "</div>";
        //ok
        
        $.ajax({
          // USED displayName .... you were using .... name ..... which is html plus name
          url: "https://wind-bow.glitch.me/twitch-api/streams/" + displayName,
          
          success: function(streamData) {
            console.log('***************************\n');
            console.log(streamData);
            console.log('***************************\n');
            var isStreaming = streamData.stream;
            var status = ""; // changed this so i could use it below
                        
            if (isStreaming === null) {
              
              status = "<div class='col-4 status'>OFFLINE</div>"; setting status here and below in else
            } else {  // added else .... its needed here
              status = "<div class='col-4 status'>ONLINE</div>";
            }
            
            var streamInfo = "<div class='row streamInfo'>" + name + status + "</div>";
            $("#streamers").append(streamInfo);
            //console.log(streamInfo);

          }
          
        });
        
        // console.log(name);
      }
    }); // $.ajax channels
    
  } // for (var i = 0; i < streamers.length; i++)
  
}); // $(document).ready

#5

Thanks for this precise answer and for the link below! I really appreciate it. However, I do not really understand the end of your first answer. I mean, what did you mean by “set this when getting info from the API”? Did you mean using “data: { }”? Can you elaborate?


#6

Thank you, that made everything clear!


#7

Sorry, I didn’t read your code carefully enough. I assumed you were working outside the AJAX success callback, given that you were targeting an entire class of elements at once.

Bear in mind that you will not necessarily receive back AJAX requests in the order they were sent, so doing anything where the index is determined by that outer for loop is doomed to failure (in fact, by the time you get back even the first of the AJAX requests, i will be the value it was after the last iteration of the loop).


#8

Yeah, I noticed that the names are always in different order. But the order in the array is always the same, shouldn’t it be kept like this until the end?


#9

It’s a scoping issue. Here’s a simple example:

for (var i = 0; i < 5; i++) {
	console.log(i); // synchronous
}
>>> 0, 1, 2, 3, 4

//compare with...

for (var i = 0; i < 5; i++) {
	setTimeout(function() {
		console.log(i);
    }, 10); // asynchronous
}
>>> 5, 5, 5, 5, 5

i is scoped to the scope that contains the loop, not to the loop itself. That means that, once the loop has finished executing, it remains at the final value within that scope.

This is because variables declared with var are “function scoped” rather than “block scoped”. A for loop creates a new block, but not a new function.

In ES6, there’s a very simple fix: change var to let. let is block scoped, so you get the results you want:

for (let i = 0; i < 5; i++) {
	setTimeout(function() {
		console.log(i);
    }, 10);
}
>>> 0, 1, 2, 3, 4

If you want an ES5-compatible fix, you have to create a new function scope, which you can do with an IIFE:

for (var i = 0; i < 5; i++) {
	(function(i) {
		setTimeout(function() {
			console.log(i);
    	}, 10);
    })(i);
}