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 trialSaqib Ishfaq
13,912 Pointswhy cant we use "querySelectorAll" instead ,? and may be avoid using for loop! i tried its not working......why?
const listItems = document.querySelectorAll('li');
listItems.addEventListener ('mouseover', () => {
listItems.textContent = listItems.textContent.toUpperCase();
});
gives me this error Uncaught TypeError: listItems.addEventListener is not a function at app.js:11
3 Answers
Jennifer Nordell
Treehouse TeacherHi there! When I was first learning, I had this thought too. But think about what you've learned about arrays thus far. That querySelectorAll
is not returning an element of the DOM, it's returning an array of elements from the DOM. You've learned already quite a few methods that exist on the Array object in JavaScript such as push
, pop
, shift
, and unshift
. The addEventListener
is not a valid method on the Array object. Here is the MDN documentation.
The addEventListener
can only be added to a compatible object such as the window or an element in the DOM. So we need to loop over the Array and attach the event listener to each element in the array. Here is the MDN documentation for addEventListener
.
Hope this clarifies things!
edited for clarification At the time I wrote this answer, I believed that a node collection was an array of DOM nodes. It is, however, not technically an array, but functions much like one. We access its elements in much the same way as an array and the NodeList
object can easily be converted to an array. However, addEventListener
is still not a valid method on the NodeList
object nor the HTMLCollection
as evidenced by this MDN documentation and here.
Saqib Ishfaq
13,912 PointsMeans there's nothing wrong using "querySelectorAll" on 'li' as long as u use [0] with it for the 1st item in that array and use loop , to go over each item in that array ,and attach "addEventListener" method to it ?? Let me giv it a go ! M out rite now but I ll once m home !
Jennifer Nordell
Treehouse TeacherWhat you just described is exactly what he does in the video. He loops over the array and attaches the event listener to every element in the array using the subscript. The first item in the array is at index 0 as you say, and the for loop begins with i = 0
. So when he says listItems[i]
, at the first iteration, i will be equal to 0.
Saqib Ishfaq
13,912 PointsOnly thing i m confused abt is the selection stage , why prefer "getElementsByTagName " over "querySelectorAll" ??? Which he did in the video ! If we can still loop through if we use querySelectorAll then why getElem......
Jennifer Nordell
Treehouse TeacherIt might not be obvious in the video and this is a bit more of an advanced topic, but a querySelectorAll()
has some parsing going on under the hood which makes it slightly less efficient than getElementsByTagName()
. So if you're searching just for all paragraphs, all divs, all spans etc, you'd probably want to use the getElementsByTagName
. However, if you need a bit of a trickier DOM traversal where you want all list items but only with the class name "my-item", then a querySelectorAll('.my-item li')
would probably be your optimal choice so that you don't have to set up a bunch of unnecessary variables to hold your DOM traversal.
Saqib Ishfaq
13,912 Pointsok i can remember that for now and may be refer to it when we proceed ahead in the course... so just to clarify m i correct to say , or rather is it a gud practice for me to use "querySelector" when we selecting an element with classes and ids and use "getElement......." when we selecting, just the tags like with no class and id etc .... ????
Jennifer Nordell
Treehouse TeacherNot exactly. What I mean is that if you don't have more than one selector, it's better to use the getElementsBy or getElementBy, but if you have more than one selector it's better to use the querySelector. I feel like this will become more clear for you as you advance.
Aakash Srivastav
Full Stack JavaScript Techdegree Student 11,638 PointsYou said addEventListener
id not a valid method on the Array object.
But isn't getElementsByTagName
too returning an array of elements with a given tag name?
The only difference is getElementsByTagName
return live HTMLCollection of elements while querySelectorAll
returns static nodeList .
But what I want to say is Both interfaces(nodeList and HTMLCollection) are collections of DOM nodes then what the meaning of -----
addEventListener is not a valid method on the Array object?
Jennifer Nordell
Treehouse TeacherAakash Srivastav Can we agree that a node list functions in much the same way as an array? It is a collection of nodes from the DOM, even if it contains only one element. You cannot add an event listener to a collection, rather you must add an event listener to a node or element in that collection. Again, check the MDN documentation for addEventListener
linked above.
Also, node lists can also be easily converted to an array (probably just for this reason). The addEventListener
is also not a valid method on a node list as documented here. However, I will update the information above with new documentation. This is also true for HTMLCollection which also does not have the addEventListener
as a valid method as documented here.
Aakash Srivastav
Full Stack JavaScript Techdegree Student 11,638 PointsThanks Jennifer Nordel , now got that completely :)
Saqib Ishfaq
13,912 Pointsi just wish it was little more clearer than it is in the videos....thanks for the help ,appreciate it!
Arun Vignesh
4,805 PointsThanks for the post and for the detailed explanation.
I too faced a similar scenario and the code was not working. After reading the comments, i changed my code and it works fine now. Sharing my code below that was updated using document.querySelectorAll() and For Of Loop:
for(let item of listItems){
item.addEventListener('mouseover', () => {
item.textContent = item.textContent.toUpperCase();
});
item.addEventListener('mouseout', () => {
item.textContent = item.textContent.toLowerCase();
});
}
Saqib Ishfaq
13,912 PointsSaqib Ishfaq
13,912 PointsJennifer Nordell This works fine, so today i exactly know what you meant couple of months ago :)