Reputation: 2425
I'm am battling with a javascript function I'm working on.
Inside a for loop I'm iterating all elements with class "visible", inside that loop I'm preforming two actions.
For some reason only 1 is valid. 2 produces an error saying:
Uncaught TypeError: Cannot call method 'setAttribute' of undefined
Even when I log elements[i] using console.log; after the first console.log call the element exists, but on the second console.log elements[i] is 'undefined'
What the hell am I missing here, this is driving me crazy, if my laptop wasn't so expensive it would have been broken by now. Help :(
Here's the function:
function hide_visable_elements()
{
// remove body EventListener
var body = document.getElementsByTagName("body");
body[0].removeEventListener("click", hide_visable_elements, true);
var elements = document.getElementsByClassName("visible");
for (var i = 0; i < elements.length; i++)
{
console.log(elements[i]); // Works like a swiss clock
elements[i].removeAttribute("class");
console.log(elements[i]); // why elements[i] is 'undefined' now ???
elements[i].setAttribute("class", "hidden"); // << turns to useless code
}
}
Upvotes: 2
Views: 1385
Reputation: 193301
getElementsByClassName
is a live NodeList
so changing className
of the items immediately affects whole list. I would recommend use querySelectorAll insead.
Plus instead of var body = document.getElementsByTagName("body");
use document.body
.
Upvotes: 1
Reputation: 1087
I think that the problem is elements[i].removeAttribute("class");
since you selected the element using a class getElementsByClassName("visible");
. I think so when you remove class attribute completely from the element things are going wrong.
Try some tweak with the code. You are not suppose to remove attribute class if you are planning to use the same element which is selected using class attribute.
Upvotes: 1
Reputation: 166071
This is because getElementsByClassName
returns a NodeList
, which is live. That is, it updates itself when the elements it refers to change.
When you remove the class
attribute from an element in the NodeList
, it gets removed from that list (since it no longer has the visible
class name).
You don't actually need to remove the attribute. Just setting it will do the job just as well. But since the NodeList
is changing as you manipulate the elements it contains, you need to count backwards through it (as each time you change one element of it, it is removed so the length decreases by one):
for (var i = elements.length - 1; i >= 0; i--) {
elements[i].setAttribute("class", "hidden");
}
Upvotes: 6