how to iterate on HTMLCollection? [duplicate]
Asked Answered
C

3

24

I have some elements in my HTML with class node-item, I access them in my component using:

let nodeItems = document.getElementsByClassName('node-item');

and when I log nodeItems it gives me a HTMLCollection[] with length 4.

I tried many ways but still can't iterate on nodeItems:

1- first try:

let bar = [].slice.call(nodeItems);
for (var g of bar){
    console.log(g); //gives me nothing
} 

2- second try:

for(let c of <any>nodeItems) {
    console.log(c); //gives me nothing
}

And I tried array iteration and object iteration but still undefined or error. also tried:

let nodeItems = document.querySelector(selectors);

But same problems.

Cordes answered 21/4, 2018 at 13:15 Comment(8)
Both approaches should work (though Array.from() would be cleaner than [].slice.call()). Are you sure the collection does contain the elements? Remember that it is a live node list. Please do console.log(nodeItems.length).Kaciekacy
Your code is working when doing it in the console, do you have more example?Epicalyx
@Kaciekacy @Epicalyx i log the nodeItems and it's give me a full HTMLCollection but when log the length it gives me 0 .Cordes
Then your actual problem is simply that the collection is empty when you try to iterate it, and it only gets filled later (when the DOM elements have been loaded).Kaciekacy
@Kaciekacy This is not a duplicate of listed questions because the question is specific to TS. I'm quite sure there's a canonical TS question somewhere though.Conway
@estus What does typescript have to do with this? Regardless whether for of compiles to iterators or array-index-counting, it should work. If logging the length gives 0, as per the OPs comment, then the problem is with using the DOM at the wrong time. Could you please re-close it?Kaciekacy
@Kaciekacy Yes, length 0 is actual problem here. It will work with for..of because it compiles to for but there will be compilation error (<any>nodeItems is ugly workaround for that). Can you list the dupes you've marked? I didn't expect it to be instantly reopened.Conway
@estus I had #14029459, and also the canonical question for console.log confusion on mutated arraysKaciekacy
C
35

nodeItems is HTMLCollection, which is array-like object.

It is iterable in modern browsers. Iterators are supported with downlevelIteration compiler option enabled, in this case it will be:

const nodeItems = document.getElementsByClassName('node-item');

for (const c of nodeItems) {
  // ...
}

Iterables can be polyfilled in older browsers. core-js provides polyfills for DOM iterables.

Otherwise nodeItems can be converted to array and iterated as usual:

const nodeItems = Array.from(document.getElementsByClassName('node-item'));

for (const c of nodeItems) {
  // ...
}
Conway answered 21/4, 2018 at 13:29 Comment(4)
i have same case but this is not helpfull to me .Selfabasement
No reason to downvote a correct answer. If it doesn't help this means that something may differ in your case. Consider asking your own question and providing stackoverflow.com/help/mcve , so the problem could be replicated by users.Conway
If I do Array.from() and then typeof nodeItems it's still an object.Shulem
@Shulem typeof won't tell you anything. Arrays are objects.Conway
I
9

Just use Array.from(document.getElementsByClassName('node-item')) or the spread operator [...document.getElementsByClassName('node-item')] and use whatever you would use on an array.

Apart from that, you could also use a normal for loop

let nodeItems = document.getElementsByClassName('node-item');
for (let i = 0; i < nodeItems.length; i++) {
    // access current element with nodeItems[i]
}
Imprimis answered 21/4, 2018 at 13:20 Comment(1)
i try the code but console logs nothing. my HTMLCollection is full and i log it and when tried [...document.getElementsByClassName('node-item')] it gives me error HTMLCollectionOf<Element>' is not an array type.Cordes
M
8

You can use spread operator on document.querySelectorAll to have an array.

Here is a snippet:

let nodeItems = [...(document.querySelectorAll('.class1'))];

for (var g of nodeItems) {
  console.log( g.innerHTML ); 
}
<div class='class1'>Text 1</div>
<div class='class1'>Text 2</div>
<div class='class1'>Text 3</div>

Doc: Spread

Mou answered 21/4, 2018 at 13:23 Comment(1)
Thank you! I can never remember the nuances of the differences of for..in and for.of, and specifically which one will actually await an await call, so that part is useless to my dysfunctional brain. But I upvoted you for the mention of using the spread operator. Works greatArbitress

© 2022 - 2024 — McMap. All rights reserved.