How to loop through selected elements with document.querySelectorAll
Asked Answered
U

10

127

I am trying loop on selected elements that queried with document.querySelectorAll, but how?

For example I use:

var checkboxes = document.querySelectorAll('.check');
for( i in checkboxes) {
  console.log(checkboxes[i]);
}

Output:

<input id="check-1" class="check" type="checkbox" name="check">
<input id="check-2" class="check" type="checkbox" name="check">
<input id="check-3" class="check" type="checkbox" name="check">
<input id="check-4" class="check" type="checkbox" name="check">
<input id="check-5" class="check" type="checkbox" name="check">
<input id="check-6" class="check" type="checkbox" name="check">
<input id="check-7" class="check" type="checkbox" name="check">
<input id="check-8" class="check" type="checkbox" name="check">
<input id="check-9" class="check" type="checkbox" name="check">
<input id="check-10" class="check" type="checkbox" name="check" checked="">

10
item()
namedItem()

My problem is that at the end this method returns 3 extra items. How can I properly do it?

Underdeveloped answered 8/9, 2012 at 10:55 Comment(3)
Hi! I'm not sure I understand your problem... Could you post your HTML code and the result you get more clearly?Padova
This article should explain it pretty well: nczonline.net/blog/2010/09/28/…Vermiform
developer.mozilla.org/en-US/docs/Web/API/Document_object_model/… developer.mozilla.org/en-US/docs/Web/API/NodeList This second link warns of your attempted approach. Use [index], for (...of...), .forEach(function () {}), or .item(index), for the easiest methods.Jews
R
62

for in loop is not recommended for arrays and array-like objects - you see why. There can be more than just number-indexed items, for example the length property or some methods, but for in will loop through all of them. Use either

for (var i = 0, len = checkboxes.length; i < len; i++) {
    //work with checkboxes[i]
}

or

for (var i = 0, element; element = checkboxes[i]; i++) {
    //work with element
}

The second way can't be used if some elements in array can be falsy (not your case), but can be more readable because you don't need to use [] notation everywhere.

Romulus answered 8/9, 2012 at 12:4 Comment(1)
Modern update: ES6 has introduced additional possibilities (for of, [...spread], …), and the ES5 [].forEach(…) hack does continue to work, beyond modern browsers (see another answer here) all supporting NodeList.forEach.Nalepka
P
102

My favorite is using spread syntax to convert the NodeList to an array and then use forEach for looping.

var div_list = document.querySelectorAll('div'); // returns NodeList
var div_array = [...div_list]; // converts NodeList to Array
div_array.forEach(div => {

// do something awesome with each div

});

I code in ES2015 and use Babel.js, so there shouldn't be a browser support issue.

Progenitor answered 29/11, 2015 at 11:7 Comment(5)
Here's to a modern answer.Skycap
Typescript shows error Type 'NodeListOf<Element>' is not an array typeHiatt
Uncaught SyntaxError: expected expression, got '...'Whyalla
Now that there's broad browser support for NodeList.forEach, this is the best answer: https://mcmap.net/q/174269/-how-to-loop-through-selected-elements-with-document-queryselectorall. See also: caniuse.com/mdn-api_nodelist_foreachPhosphocreatine
var is modern?Sloppy
I
65

It looks like Firefox 50+, Chrome 51+ and Safari 10+ now all support the .forEach function for NodeList objects. Note—.forEach is not supported in Internet Explorer, so consider one of the approaches above or use a polyfill if IE support is required.

https://developer.mozilla.org/en-US/docs/Web/API/NodeList/forEach

const paragraphs = document.querySelectorAll('p');
paragraphs.forEach(p => console.log(p));
<p>paragraph 1</p>
<p>paragraph 2</p>
<p>paragraph 3</p>
<p>paragraph 4</p>
<p>paragraph 5</p>
Indicant answered 27/2, 2017 at 19:26 Comment(3)
or [...document.querySelectorAll('p')].forEach(p => console.log(p));Randarandal
In 2023, I believe this is now the right approach. No need for spread, Array.from or for inLecher
Is it safe/recommendable to use p.remove with this?Dowden
R
62

for in loop is not recommended for arrays and array-like objects - you see why. There can be more than just number-indexed items, for example the length property or some methods, but for in will loop through all of them. Use either

for (var i = 0, len = checkboxes.length; i < len; i++) {
    //work with checkboxes[i]
}

or

for (var i = 0, element; element = checkboxes[i]; i++) {
    //work with element
}

The second way can't be used if some elements in array can be falsy (not your case), but can be more readable because you don't need to use [] notation everywhere.

Romulus answered 8/9, 2012 at 12:4 Comment(1)
Modern update: ES6 has introduced additional possibilities (for of, [...spread], …), and the ES5 [].forEach(…) hack does continue to work, beyond modern browsers (see another answer here) all supporting NodeList.forEach.Nalepka
G
32

With ES6, there is a static method Array.from to take advantages of Array non-static methods (map, filter, ...) :

Array.from(document.querySelectorAll('div')).forEach((element,index) =>
{

     // handle "element"

});

Another use of Array.from since querySelector provides item method:

var all = document.querySelectorAll('div');
// create range [0,1,2,....,all.length-1]
Array.from({length: all.length}, (v, k) => k).forEach((index) => {
     let element = all.item(index);
});
Gaucho answered 7/9, 2016 at 18:31 Comment(5)
But you can just do document.querySelectorAll('div').forEach(item => console.log(item)) ... why do you need to wrap it with Array.from ?Ethiopia
@Ethiopia you wouldn't need to wrap for .forEach, but would if you wanted to use another Array method like .map or .filter because .querySelectorAll returns a NodeList, and not an Array. I'd choose this approach if I wanted to make sure I was working with arrays and wanted to keep data/API calls consistent.Indicant
Then [...document.querySelectorAll('div')].forEach((element,index) => { // handle "element" }); could do itRandarandal
@Randarandal are dots ... necessary to make it work ?Emancipated
@Salem. Yes it seems as document.querySelectorAll stores a nodeList and we send it to Array.forEach method. In one line we get the nodeList, destructure it in an array and send it to forEach method.Randarandal
H
26

A nice alternative is:

[].forEach.call(
    document.querySelectorAll('.check'),
    function (el) {
        console.log(el);
    }
);

but as pointed out, you should use a for loop.

Hottempered answered 24/12, 2013 at 11:11 Comment(3)
The overhead is more than just using a for loop unfortunately, it's a neat solution though.Estoppel
Interesting post on this method: toddmotto.com/ditch-the-array-foreach-call-nodelist-hackIncantatory
If taking this approach, it would be best to do the querySelectorAll before and pass the result into the forEach loop (eg. var elements = document.querySelectorAll('.check'); [].forEach.call(elements, ...);). Otherwise you end up unnecessarily making the same DOM query over and over again on each iteration of the loop.Olszewski
H
6

A Main Takeaway:

The type matters.

.map will not work directly on a NodeList but will on an Array.

Compare these: Array.prototype.map() NodeList.forEach()

Options:

ES6 available?

  1. The spread operator [...element_list] then Array.map()
  2. Array.from() on a NodeList.forEach()

ES6 NOT available?

  1. NodeList.forEach()
  2. A "for loop"
Hypophysis answered 16/3, 2021 at 21:8 Comment(0)
I
6
// for class
for (const elem of document.querySelectorAll('[class=".check"]')){
    //work as per usual
};

// for name
for (const elem of document.querySelectorAll('[name="check"]')){
    //work as per usual
};

// for id
for (const elem of document.querySelectorAll('[id="check-1"]')){
    //work as per usual
};

This provides me with flexibility on what element I would like to work with.

Inman answered 5/7, 2022 at 6:41 Comment(1)
Your first example won't work. The value .check won't match anything and would only match class attributes with that exact value (not with other classes). It should just be querySelectorAll('.check').Indenture
I
1

For me, the most clean and accessible is the for...of statement, this perfect syntax executes a loop that operates on a sequence of values sourced from an iterable object. The second options for me is the three-dots operator (...), if ES6 is available, this is also a very good options as my personal opinion. Finally, forEach if you are building big app and you want to provide support for most of the browsers out there this might give you some headaches.

const lis = document.querySelectorAll('li')

let results = {
  'for': [],
  'forEach': [],
  'three-dots': [],
}

// ES6 bellow
for (const li of lis) {
  results['for'].push(li)
}

// ES6 above
[...lis].forEach((li) => results['three-dots'].push(li))

// Most browsers support it 
lis.forEach(li => results['forEach'].push(li))

console.log({results})
<u>
  <li>Item 01</li>
  <li>Item 02</li>
  <li>Item 03</li>
  <li>Item 04</li>
  <li>Item 05</li>
  <li>Item 06</li>
  <li>Item 07</li>
  <li>Item 08</li>
</u>
Iodometry answered 20/5, 2022 at 9:42 Comment(0)
O
0

The shortest and cleanest way to be able to use any regular Array methods, or in your case a for in loop on a NodeList, is to spread it into an array as you fetch it:

const checkboxes = [...document.querySelectorAll('.check')];

for (i in checkboxes) {
  console.log(checkboxes[i]);
}
Ossetia answered 1/11, 2021 at 16:48 Comment(0)
H
-1

U can select all elements using querySelectorAll method. It will return an array of nodeList.

Lets say u want to select all p tags

<p>paragraph 1</p>
<p>paragraph 2</p>
<p>paragraph 3</p>
<p>paragraph 4</p>
<p>paragraph 5</p>
const paragraphs = document.querySelectorAll('p');

Now the paragraphs has a forEach method which can be used to loop through the nodelist

paragraphs.forEach(console.log); (logs node)
Hydrus answered 12/11, 2021 at 10:57 Comment(2)
As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.Solve
@Solve pls check the answer clearly before doing any comments. Stack overflow please check this bot bugHydrus

© 2022 - 2024 — McMap. All rights reserved.