Maybe someone else asked the same questions , but i didnt find any similar results in questions that may already have your answer so i will go ahead ask my question.I know that is alive list and when the first className change the list is going from 3 items to 2 . So the i now is 1 so thats why it skipped the "second item" from the list. Whats the best way to include all the items in a live Node List in loops ? (Maybe use a static one?)
var hotElements = document.getElementsByClassName("hot");
var i;
var len = hotElements.length;
for ( i= 0; i < len ; i++) {
hotElements[i].className = "pink";
}
.hot {
background-color: red;
color: black;
font-size: 20px;
weight: 700;
}
.cool {
background-color: blue;
font-size: 25px;
}
.pink {
background-color: pink;
font-size: 35px;
<h1 id="header"> List King </h1>
<h2> Buy grocceries </h2>
<ul>
<li id="one" class="hot"> Fresh </li>
<li id="two" class="hot"> Fresh 1</li>
<li id="three" class="hot"> Fresh 2 </li>
<li id="one" class="cool"> Fresh </li>
<li id="two" class="cool"> Fresh 1</li>
<li id="three" class="cool"> Fresh 2 </li>
</ul>
One approach that was used in the past is to loop over the collection backwards, that way if an item is removed it doesn't affect the position of any of the remaining elements:
var hotElements = document.getElementsByClassName("hot"),
i;
for (i = hotElements.length - 1; 0 <= i; i--) {
hotElements[i].className = "pink";
}
One advantage to this approach over the while(hotElements.length > 0)
solution that NikxDa proposed is that it doesn't rely on elements getting removed if you were conditionally applying the new className
instead of doing to every element.
You could also convert the live node collection to a real array that will not change.
Using ES2015 it is quite easy to do using the spread syntax:
var hotElements = document.getElementsByClassName("hot");
[...hotElements].forEach(function (element) {
element.className = "pink";
});
You can also do it in ES5 with a little more code:
var hotElements = document.getElementsByClassName("hot");
Array.prototype.slice.call(hotElements).forEach(function (element) {
element.className = "pink";
});
Using slice
to convert to an array won't work in IE < 9... but at this point in time that probably isn't a concern.
One more approach would be to use querySelectorAll. It returns a non-live NodeList, so if you used it to find the elements you could still loop over it forwards:
var hotElements = document.querySelectorAll(".hot"),
i,
len = hotElements.length;
for (i = 0; i < len ; i++) {
hotElements[i].className = "pink";
}
Interesting related article: A comprehensive dive into NodeLists, Arrays, converting NodeLists and understanding the DOM