Gaurav Aggarwal Gaurav Aggarwal - 7 months ago 27
Javascript Question

document.querySelectorAll() function not working on all elements

I am using

document.querySelectorAll()
function to catch
<a>
in my list of
<li>
but the function is not working on all elements i have to define like this
document.querySelectorAll('//elements')[0]
,
document.querySelectorAll('//elements')[1]
if i define like this it works on element on that index only.

I don't think its good to define like this for all elements. Can anyone tell me please where i am wrong why its not working on all elements.

Here is my current code

HTML

<ul class="questions">
<li>
<a href="#" class="clearfix"><span class="faq_name">My Account</span><span class="arrow"><img src="images/plus.png"></span></a>
<div class="answer_box">
<p>Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet. </p>
</div>
</li>
<li>
<a href="#" class="clearfix"><span class="faq_name">Categories</span><span class="arrow"><img src="images/plus.png"></span></a>
<div class="answer_box">
<p>Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet. </p>
</div>
</li>
<li>
<a href="#" class="clearfix"><span class="faq_name">Trouble with check-in</span><span class="arrow"><img src="images/plus.png"></span></a>
<div class="answer_box">
<p>Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet. </p>
</div>
</li>
</ul>


JS

document.querySelectorAll('.questions li a').onclick = function() {myFunction()};
function myFunction(){
alert('asd');
};

Answer

querySelectorAll returns a collection of elements. The DOM doesn't have a "set-based" feature letting you assign handlers to the entire set in one statement (the jQuery library does, if you fancy using it), you have to use a loop.

For example:

Array.prototype.forEach.call(
    document.querySelectorAll('.questions li a'),
    function(element) {
        element.onclick = myFunction;
    }
);
function myFunction(){
    alert('asd');
}

There, we use Array#forEach to loop through the collection (because it can be used on any array-like object, not just arrays). You have several other options outlined in the "array-like" part of this answer.


Side note 1: I used MyFunction directly above since wrapping it in a function that just calls it seems unnecessary, but that will change what arguments it receives, so add a wrapper if needed.

Side note 2: While I didn't change it above, I strongly recommend using addEventListener (and attachEvent if you have to support IE8 or the broken "compatibility mode" of IE9-IE11) instead of onclick.

Side note 3: For this specific use case, you might look into event delegation rather than adding a handler to each element. In event delegation, you add a handler to a container that has all your links in it (could be document.body, but usually there's a container closer to them that's more appropriate), and then when the event occurs, you see if it passed through a matching element while bubbling.

Side note 4: On those occasions where you just want the first match, intead of querySelectorAll(...)[0], use querySelector(...). It returns the first match, or null if nothing matches.