I would like to...
I thought this code would work but for some reason it breaks the loop after the first instance and the element's class names are never changed. No frameworks please.
function example()
{
var elementArray;
elementArray = document.getElementsByClassName("exampleClass");
for(var i = 0; i < elementArray.length; i++)
{
// PERFORM STUFF ON THE ELEMENT
elementArray[i].setAttribute("class", "exampleClassComplete");
alert(elementArray[i].className);
}
}
EDIT (FINAL ANSWER) -- Here is the final product and how I have implemented @cHao's solution within my site. The objective was to grab an assortment of timestamps on the page and change them to time ago. Thank you all for your help, I learned a ton from this question.
function setAllTimeAgos()
{
var timestampArray = document.getElementsByClassName("timeAgo");
for(var i = (timestampArray.length - 1); i >= 0; i--)
{
timestampArray[i].innerHTML = getTimeAgo(timestampArray[i].innerHTML);
timestampArray[i].className = "timeAgoComplete";
}
}
The problem is that the NodeList returned to you is "live" - it changes as you alter the class name. That is, when you change the class on the first element, the list is immediately one element shorter than it was.
Try this:
while (elementArray.length) {
elementArray[0].className = "exampleClassComplete";
}
(There's no need to use setAttribute()
to set the "class" value - just update the "className" property. Using setAttribute()
in old versions of IE wouldn't work anyway.)
Alternatively, convert your NodeList to a plain array, and then use your indexed iteration:
elementArray = [].slice.call(elementArray, 0);
for (var i = 0; i < elementArray.length; ++i)
elementArray[i].className = "whatever";
As pointed out in a comment, this has the advantage of not relying on the semantics of NodeList objects. (Note also, thanks again to a comment, that if you need this to work in older versions of Internet Explorer, you'd have to write an explicit loop to copy element references from the NodeList to an array.)
Most DOM functions that return a list of elements, return a NodeList rather than an array. The biggest difference is that a NodeList is typically live, meaning that changing the document can cause nodes to magically appear or disappear. That can cause nodes to move around a bit, and throw off a loop that doesn't account for it.
Rather than turning the list into an array or whatever, though, you could simply loop backwards on the list you get back.
function example()
{
var elements = document.getElementsByClassName("exampleClass");
for(var i = elements.length - 1; i >= 0; --i)
{
// PERFORM STUFF ON THE ELEMENT
elements[i].className = "exampleClassComplete";
// elements[i] no longer exists past this point, in most browsers
}
}
The liveness of a NodeList won't matter at that point, since the only elements removed from it will be the ones after the one you're currently on. The nodes that appear before it won't be affected.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With