How to loop through htmlcollection object?

2.3k views Asked by At

I have looked at almost every question that has been asked here about htmlcollection.

So I have a div and I am fetching data and creating divs inside this div with ajax so they are not hardcoded.

this is how div look like before I fetch the data

    <div id="tivvits"></div>

this is how div#tivvits looks like after I call function show_all_tivvits(); show_all_tivvits() is a function where I create a ajax request and create new divs such as div#tivvit-21, div#tivvit-22, etc.

    <div id="tivvits">
        <div id="tivvit-19" class="grid-container">...</div>
        <div id="tivvit-20" class="grid-container">...</div>
    </div>

this is part of the js file

    document.addEventListener("DOMContentLoaded", function(){
    
        show_all_tivvits();
        var t = document.getElementById('tivvits');
        const j = t.getElementsByClassName("grid-container");
        const k = Array.prototype.slice.call(j)
        console.log(k);
        for (var i = 0; i < k.length; i++) {
            console.log(k[i]);
        }

    });

what I wanted to do in show_all_tivvits() function is I want to get the divs that are already in the div#tivvits and that way I am not gonna create them again but the problem is when I use console.log() to print out document.getElementById('tivvits').getElementsByClassName('grid-container') there are items in the htmlcollection but when I print out length it returns 0.

one more thing when I open inspect>source in chrome my index.php doesn't have updated div#tivvits. I have tried almost every way to loop this htmlcollection but it is not working.

list of things I have tried;

Array.from(links)

Array.prototype.slice.call(links)

[].forEach.call(links, function (el) {...});

HTMLCollection.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];

HTMLCollection.prototype.forEach = Array.prototype.forEach;
2

There are 2 answers

0
Jack Fleeting On BEST ANSWER

It's not really clear, but are you looking for something like this?

targets = document.querySelectorAll('#tivvits > .grid-container')
for (let target of targets)
  {console.log(target.id)}

This should select all <div> nodes which are direct children of the <div id="tivvits"> node and have a class attribute with the value "grid-container", and extract from them the attribute value of the id attribute.

5
mplungjan On

The world has moved on.

The older versions

const arrayLikeCollection = Array.prototype.slice.call(htmlCollection) 

and

[].forEach.call(htmlCollection, function (el) {...});

could be written

[...htmlCollection].arrayMethod(....)

Then we got an update to htmlCollection so it supported .forEach out of the box. However the OTHER array methods like map, filter, some and every still needs the hmtlCollection to be cast to an arrayLike collection.

In 2024, the consensus is to use Array.from due to the very descriptive name.

It is my method of choice too now, since the array spread can generate annoying errors if your statement on the line above does not have a semicolon:

const collection = document.querySelectorAll('.someClass')
[...collection].someMethod(...) // the [] is seen as belonging to the line before

So here is the currently recommended way

window.addEventListener("DOMContentLoaded", () => { // when the elements are available
  const getIds = () => {
    const gridContainers = document.querySelectorAll("#tivvits .grid-container");
    const ids = Array.from(gridContainers).map(div => div.id);
    return ids;
  };
  const idsAtLoadTime = getIds(); // can be called elsewhere, like at the end of an AJAX call
  console.log(idsAtLoadTime)
});
<div id="tivvits">
  <div id="tivvit-19" class="grid-container">...</div>
  <div id="tivvit-20" class="grid-container">...</div>
</div>