elad.chen
elad.chen

Reputation: 2425

variable turns to undefined inside a for loop

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.

  1. elements[i].removeAttribute("class");
  2. elements[i].setAttribute("class", "hidden");

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

Answers (3)

dfsq
dfsq

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

Aneesh Mohan
Aneesh Mohan

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

James Allardice
James Allardice

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

Related Questions