The Twitch API Challenge

  1. You have an extra closing curly brace } at line 26.

  2. data.data is an array, data.data[0] is the object inside the array.

  3. You have to check both that data.data is not undefined (or simply that it is Truthy) and check that the array is not empty (check the length of the array) before using it in Object.entries. Move the if statement up before the loop and fix the logic for the if statement.

  4. As the code is now, you are always going to add the last object to the DOM when clicking the button.

Okay, this is what I have now. What do I still have wrong here? And what do I do to display the info for the users who aren’t streaming currently?

You might as well get used to this now, whenever something doesn’t work, check for typos first. They will get you every time.

  1. You are missing the s on Object.entries

  2. You are missing the r in afterbegin.


As for the overall logic:

The main issue is with the click handler. If you remove it you will see you are adding all the valid array objects to the DOM. The question is how and when to display the data.

A fairly simple solution would be to have two elements. One for online streams and one for off-line streams. Add the data to the two elements but have them hidden by default using CSS. For the online streams, it would be the API data and for the off-line streams it would be some text message like “${stream} is off-line”.

Then you just toggle the visibility of the element(s) when you click the button(s). You can give the elements a class that hides them (e.g. .hide { display: none }) and toggle it using someElement.classList.toggle("hide").

The click handling should be outside the loop. The loop just fetches the data and adds it to the DOM. The click handlers just toggle the display.

What I want to do is actually to have them all show when the user first gets to the app and then toggle visibility depending on the buttons clicked. And I want to have each stream be there as a whole in one div with the id of new-stream. Right now each key-value pair is in a separate div and the offline ones are repeated. Here is the code.

I’ll try to get that and the functionality of the “all” button to work first and then do the other two buttons.

So I’d like some help with getting this to work correctly if it’s not too much trouble. Thanks in advance.

Edit: I especially need some help in putting all of the info about a single stream/user in one single div element. And why is there just one streamer being repeated for the offline streamers?

You may want to try using template literals for building the HTML you insert into the page. Here is a good article to get you started.

You forgot to declare the streamer variable in the for…in loop (use const or let).

About the streamer variable in the loop, I was trying to use the one I’d declared right outside the loop.

I’ll look at that link you gave.

Edit: So you’re saying to manually create the HTML as strings using template literals? Why shouldn’t I use the DOM methods I’m using right now?

It’s up to you. I find using template literals much cleaner.

I can write HTML as I would normally write it, I don’t have to create elements or set attributes and I don’t need to access the innerHTML/text to set the content. It behaves more like a templating language. I think once you start to write more complex HTML you will see the benefits.

I’ll stick with the DOM methods here.

Anyway, how do I get all of the data for each streamer to appear in a single div? Right now there’s a separate div for each piece of data about a given streamer. My current code.

And how do I get those images whose URLs are in there to show up (the thumbnails)?

  1. Move the div creation up and out of the inner for loop. But I assume you are not just going to dump all the raw data into a single div.

  2. You have not made an img element and you are not setting the src attribute, you are just adding the image data in a div as a string.

I would suggest you first write out the HTML like it was a static page. Figure out what elements you need and what data you need. Then convert that to dynamically created elements and add the data where appropriate.

Secondly, the way you are writing the code is not maintainable. Think about how you can break it up into smaller pieces (functions) before you start to write more code. Think about where it makes sense to do things, e.g. does it make sense to keep querying the same DOM element inside a loop, or adding the same event listener over and over again. Think about where data “lives” and how code that use that data can get to it, functions can take arguments and return data. Create small chunks of code that has clear responsibilities, make code reusable when possible.

Take the time to learn more about the tools and techniques you have to use:

https://www.youtube.com/results?search_query=Dom+Manipulation

This is what I have now. I’m putting the code for the second .then into another function. But whether or not I do that, currently nothing shows up below the three buttons I have.

Any help is appreciated. Thanks.

  1. You are using a for...in loop which makes the streamer variable the array index, not the string. Use a for...of loop.

  2. The function showStreamerData is not getting passed any data. When you call it, pass the data, and in the function definition create a parameter to accept the data.

// definition
function showStreamerData(data) {
...code
}

// Invocation
showStreamerData(data)
  1. You are calling insertAdjacentElement on onlineStreamersDiv, that is not what you name the variable, you named it onlineStreamsDiv
onlineStreamsDiv > Correct
onlineStreamersDiv > Wrong

Open the browser console, check for errors, keep it open when you work.

Whenever you get a value or change a value, log it out to the console to see that it is what you expect it to be.

Thanks for the reply.

Here’s the current code. I’ve got the divs, but the image thumbnails still aren’t showing and I think at least part of the reason is the image’s dimension values being enclosed in curly braces (if that’s the case, how do I fix that?). Also there should be more people offline than the one whose name is showing up; how do I get all of the names to show up?

  1. You can either replace them with numbers (dimensions) or remove them. I would suggest just removing them so you don’t get any strange aspect ratio. Then do the image sizing in the CSS.

Read the replace docs.

// remove 
thumbnail.src = value.replace(/-{width}x{height}/, '');

// replace
thumbnail.src = value.replace(/{width}x{height}/, '1200x800');
  1. The only reason why you even have access to the streamer variable in the showStreamerData function is that you didn’t declare the variable, so it is global. You will always just get the last value it was set to in the loop (or undefined if you declare it using let). Declare it in the loop first (always declare your variables) then pass it to the function just like you are passing the data (remember you also need a parameter).

have you solved that ? it looks really difficult

I removed the global declaration of streamer, declared it using let in the loop, and passed it into showStreamerData. So that problem is fixed now.

Now to remove the height and width properties of the image URL, do I look at in a loop and then find and delete the height and width properties? Current code.

@jaminson: It’s not really that hard. I guess you just need to know what you’re doing.

I got it. I wonder if it looks fine. Code.

What are you asking about, the images or the code?

The images look fine.

The code looks better now. I’m still not sure why the event handlers are inside the showStreamerData function. You may also want to wrap the streamer loop in a function that you can call as needed.

Are you suggesting to put all of this:

for (let streamer of streamersArray) {
  fetch(`https://wind-bow.glitch.me/helix/streams?user_login=${streamer}`)
  .then(response => {
    return response.json();
  })
  .then(data => {
    showStreamerData(data, streamer);
  })
  .catch(err => {
    console.log(`Error: ${err}`);
  });
}

in a separate function?

I just put the click handlers right below the declarations for onlineStreamsDiv and offlineStreamsDiv by the way. And it looked streamer inside the loop would be better off being const, so I made it const.

Alright. Put the main streamer loop in its own function. Here’s the latest update (so you don’t have to scroll up to find a link).

  1. Yes, a function is better. Otherwise, if you need to get the data again you have to refresh the page. Now you can just call the function.

  2. Yep, that’s good. No need to keep adding the event listeners every time the showStreamerData function is called.

  3. Both work. Just remember you can’t reassign streamer if you use a const. Might be irrelevant, might become relevant, just something to keep in mind.

The second User Story for it mentions being able to click on the status output and being able to get to freeCodeCamp’s Twitch channel. Is it referring to the status of whether they’re online or not and their streaming details if they’re online? In that case, would it be good to have “live” in “type: live” for those who are online link to their Twitch channel and for those who are offline just make the line mentioning that this streamer is offline a link?