JavaScript JavaScript and the DOM Getting a Handle on the DOM Selecting Multiple Elements

Michael Williams
PRO
Michael Williams
Pro Student 8,058 Points

Why can't I use querySelector here?

I'm confuses about a few things, even after watching the videos a few times.

First, I understand the correct answer:

let listItems = document.getElementsByTagName("li")

But why can't you use:

let listItems = document.querySelector("#rainbow")

Secondly, going back to the correct answer for this challenge, if there were other li's in the HTML in other sections, would the correct answer return all of them, too? If not, why? And also, how does it know where to find only the lis we want?

index.html
<!DOCTYPE html>
<html>
  <head>
    <title>Rainbow!</title>
  </head>
  <body>
    <ul id="rainbow">
      <li>This should be red</li>
      <li>This should be orange</li>
      <li>This should be yellow</li>
      <li>This should be green</li>
      <li>This should be blue</li>
      <li>This should be indigo</li>
      <li>This should be violet</li>
    </ul>
    <script src="js/app.js"></script>
  </body>
</html>
js/app.js
let listItems = document.querySelector("#rainbow");
const colors = ["#C2272D", "#F8931F", "#FFFF01", "#009245", "#0193D9", "#0C04ED", "#612F90"];

for(var i = 0; i < colors.length; i ++) {
  listItems[i].style.color = colors[i];    
}

2 Answers

Ruben Ponce
Ruben Ponce
Full Stack JavaScript Techdegree Student 12,035 Points

querySelector() will return the <ul> tag, not the collection of list items. Also remember that querySelector() will only return one element, and not lists. However, if you wanted to select the list items you could use querySelectorAll('#rainbow li'), because querySelectorAll() is used for selecting multiple items.

Michael Williams
Michael Williams
Pro Student 8,058 Points

Ooooooooh. Okay, even if I did have .querySelector("#rainbow") it doesn't work, because .querySelector("#rainbow") will read the <ul> element and not grab the first item because it's part of a list. In other words anything labeled as a list it steers clear of. I thought it'd grab the first item of whatever you ask it to find, even if it's in a list. That makes so much more sense now.

Michael Williams
Michael Williams
Pro Student 8,058 Points

One more question. Wouldn't document.querySelectorAll("#rainbow") work, too? I feel like I used that for my answer, but it wouldn't work. Or do you specifically have to have (#rainbow li) in there?

Stephen Anim
Stephen Anim
Front End Web Development Techdegree Graduate 20,170 Points

Michael,

If you use document.querySelectorAll("#rainbow"), you will only be selecting all elements with the ID of "rainbow." In this case, it means just the one <ul> node. (Since an ID is being used, there should be another element/node with the same ID anyway.)

You do have to use (#rainbow li) or (#rainbow > li) to select the <li> nodes inside of the <ul id="rainbow"></ul>.

Are you familiar with how CSS selectors work? Selecting elements in JavaScript using querySelector or querySelectorAll is designed to work the same way. Using (#rainbow li) would select any <li> that is a descendant of the <ul id="rainbow"></ul>, including <li> nodes that are nested inside of other <li> nodes. Using (#rainbow > li) would select only the <li> nodes that are direct children (one level down) of the <ul id="rainbow"></ul>.

Stephen Anim
Stephen Anim
Front End Web Development Techdegree Graduate 20,170 Points

Hello, Michael Williams. I only just saw your request for me to answer this question.

Ruben Ponce provided the same answer I would have given to your first question.

Secondly, going back to the correct answer for this challenge, if there were other li's in the HTML in other sections, would the correct answer return all of them, too? If not, why? And also, how does it know where to find only the lis we want?

To answer this second part, using getElementsByTagName("li") would indeed select all <li> nodes in the HTML document. If there were other <li> nodes on the page, then Ruben Ponce's suggestion of querySelectorAll('#rainbow li') would have specified just the desired set of list items.

If you ever want to know exactly what it is you are selecting (outside of the closed environment of an embedded code challenge, of course), log your selection to the console and see what is returned. There have been many times along my coding journey when I wasn't sure what my code was doing exactly and console.log() made everything clear.

As Ruben Ponce said, you'll find that querySelector() returns a single instance of a node, specifically, the first one it finds (index of 0). querySelectorAll() returns an array of nodes, which means you can use array methods on the results. For instance, you can loop over them like you would an array, select items by index number, and so on. Very useful. And super fun.

Also note that the selector getElementById() also returns just one node, while the selectors that begin with the plural getElementsBy... return an array.

From the badges in your profile, it looks like you're on one of the JavaScript Tracks. I'm guessing you're close to learning jQuery. The jQuery selector $() works the same as querySelectorAll() in that it returns an array. Knowing that will come in handy quite often.

Happy coding.

Michael Williams
Michael Williams
Pro Student 8,058 Points

Thank you Stephen. Your and Ruben's answers were very helpful, especially the part of using the console to help figure things out.