Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

JavaScript JavaScript and the DOM (Retiring) Getting a Handle on the DOM Selecting Multiple Elements

Stephen O'Dell
Stephen O'Dell
1,596 Points

Selecting multiple elements using multiple criteria (ie, using both tag name and ID)

This challenge took me way too many tries to get it right, and then when I did, I still wasn't sure that I did it the way Treehouse wanted me to do it. I eventually got a correct answer (two, actually), but I couldn't find a similar example in the previous lessons, so I have this vague feeling that I just got lucky.

Task: On line 1 of app.js, set the variable listItems to refer to a collection. The collection should contain all list items in the unordered list element with the id of rainbow.

Question 1: Is the methodology that you're looking for to use a double .getElement? In other words:

let listItems = document.getElementById('rainbow').getElementsByTagName('li');

Question 2: This also worked, but I’m not sure why, so … how does one know whether we need a .getElement or a .querySelector?

let listItems = document.getElementById('rainbow').querySelectorAll('li');

I found numerous Q&As in StackOverflow etc, but in nearly every case the discussion was marked “closed as primarily opinion-based,” without a clear, definitive answer.

Thanks!

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;
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

Jennifer Nordell
seal-mask
STAFF
.a{fill-rule:evenodd;}techdegree
Jennifer Nordell
Treehouse Teacher

Hi there! A getElementById will return one element. Because id's are unique on that page. For example, you may not have an unordered list with the id "rainbow" on that page and then have another div somewhere else with the id "rainbow". This is why getElementById is not named getElementsById :smiley: So a querySelectorAll returns a set of elements. But the same can be said for getElementsByTagName.

But I have a third solution, which I think is slightly more elegant. This is, again, just my personal opinion. I did it like this:

let listItems = document.querySelectorAll("#rainbow li");

This selects all list items within the element that has the id of "rainbow".

Hope this helps clarify a bit! :sparkles:

Steven Parker
Steven Parker
231,271 Points

:sparkles: it's been a while since you posted while I was composing. It was fun to see that we both had the same solution.

Stephen O'Dell
Stephen O'Dell
1,596 Points

Thanks! I should have researched query selectors first. Had no idea you could include an ID and tag in one query like that. Again, thanks!

Paul Brown
Paul Brown
7,057 Points

I'll go Jennifer maybe one better.

I was also stumped on this one for quite a while, and did NOT like my original solution which was to just use "li", which happened to work in this case b/c there were no other <li> elements in the html. But using MDN's spex, I followed the link for querySelectorAll's argument, CSS selectors. This led me to the answer that I'd been TRYING to figure out:

let listItems = document.querySelectorAll('#rainbow > li');

The greater than symbol specifies direct children of an element, and in this particular case, this ends up being equivalent to Jennifer's option. But for future reference, it might come in handy!

Jennifer Nordell
seal-mask
.a{fill-rule:evenodd;}techdegree
Jennifer Nordell
Treehouse Teacher

Paul Brown yes, this would for work for this example, however, if we were to modify that list to contain nested lists then it would no longer select all list items inside the parent unordered list but rather just those that are direct descendants. That works in this case, but what if the unordered list were divided up into other unordered lists containing shades of those colors?

Also, in my opinion, it's a little redundant to say the "direct descendant of an unordered list that is a list item" as the only allowed direct descendent of an unordered list is a list item. The only reason for that kind of specificity would be if you wanted to skip any list items in nested lists.

Steven Parker
Steven Parker
231,271 Points

:point_right: If it passes, you did well.

I believe the concept that there are often many ways to solve the same problem was mentioned in the course. The "right" way is any way that does the job. In some situations where time is critical, the "right" way may be the one that does the job the fastest. I don't think that matters here.

I also had two ideas for solving this one, but both of mine use only one selector method call:

let listItems = document.querySelectorAll("#rainbow li");     // this was my first thought
let listItems = document.getElementById("rainbow").children;  // but this also works

I didn't do any performance analysis, but I suspect the second one might be faster. But I like the first one because it is a bit more compact.

Stephen O'Dell
Stephen O'Dell
1,596 Points

Thanks, Steven. I stumbled onto the dot-children version a little bit later, but was still messing up somewhere and couldn't get it to work. So, thanks!