0

For my project, I am required to get the collection of all the elements which have the same class. So, I am doing it with getElementsByClassName.

var tabs = document.getElementsByClassName("tab");

if (tabs) {
    for (var i = 0; i < tabs.length; i++) {
        var tab = tabs[i];
        console.log(tab);    // which outputs as 'undefined'..
        console.log(i);    // which outputs the nos of the total nodes available with class 'tab'
    }
}

I have to retrieve all those elements(which has class 'tab') and apply it another class (say 'bat')..

My question is, why it consoles out undefined as above?? and how can I be able to iterate through all the required nodes sequentially. Is there any code available which can do this??

EDIT ::

Forget to add it..

When clicked on any tab which has 'tabs' class, it always returns the same result..

var tabs = document.getElementsByClassName("tab");

if (tabs) {
    for (var i = 0; i < tabs.length; i++) {
        var tab = tabs[i];
        tab.addEventListener("click", function() {
            console.log(tab[i]);  // always returns undefined
            console.log(tab);  // always returns the last element in the list
            console.log(i);  // always returns the length of that list (in my case its 3)
        }, false);
    }
}

How can I be able to iterate through all the available elements sequentially.

bantya
  • 576
  • 11
  • 23
  • What's the output of console.log(tabs)? – roland Dec 29 '15 at 20:15
  • console.log(tabs) provides the list of all the available elements with class-name 'tab'.. – bantya Dec 29 '15 at 20:18
  • 1
    Works as expected [here](http://codepen.io/paulroub/pen/rxWGEL) - logs each tab, followed by 0, 1, and 2. Can you show a non-working example? – Paul Roub Dec 29 '15 at 20:24
  • Is that the actual code above? – epascarello Dec 29 '15 at 20:38
  • epascarello, The edited code is my actual code.. – bantya Dec 29 '15 at 20:46
  • 2
    `tab[i]` is definitely a typo for `tabs[i]`. Beyond that, take a look at [adding 'click' event listeners in loop](http://stackoverflow.com/questions/8909652/adding-click-event-listeners-in-loop) to learn about closures and how they're giving you trouble. – Paul Roub Dec 29 '15 at 21:26

3 Answers3

1

You can change a NodeLiist into an array. Btw, your tab[i] should be tabs[i] I think.

var tabs = document.getElementsByClassName('tab');
var tabArray = Array.prototype.slice.call(tabs);
for(var i = 0; i < tabArray.length; i++) {
     console.log(tabArray[i].id);
     console.log(i);
     tabArray[i].innerHTML = "t"+(i+1);
     
};
<div id="t1" class="tab">t</div>
<div id="t2" class="tab">t</div>
<div id="t3" class="tab">t</div>
<div id="t4" class="tab">t</div>
<div id="t5" class="tab">t</div>
<div id="t6" class="tab">t</div>
<div id="t7" class="tab">t</div>
<div id="t8" class="tab">t</div>
zer00ne
  • 41,936
  • 6
  • 41
  • 68
1

Be careful with getElementsByClassName(), as said in mozilla docs the return is a array-like object not a array. Another point is that return is a live HTMLCollection so if you want to change the class name through a loop the collection will be live updated on the fly and will cause unexpected behaviors. I made a example with class change case. Check complete code on link below.

http://codepen.io/renatocolaco/pen/VemMNy

function btnClick(event){

event.preventDefault();

//action goes here
var boxes = document.getElementsByClassName("box");

console.log("fouded elements: " + boxes.length);
var element = boxes.item(0);
while(element){
    element.className = "another_box";
    element = boxes.item(0);
}

//doesn't work
//var cache = boxes.length;
//for(var i = cache; i < boxes.length; i++){
//    console.log(boxes[0]);
//    boxes[0].className = "another_box";
// }

//doesn't work
//Array.prototype.forEach.call(boxes, function(element, index, array){

    //array[index].className = "another_box";

//});
}

Update: The second problem, when you are adding event to the tabs, you have a closure problem. This is because, at the point that the onclick method is invoked (for any of the tabs), the for loop has already completed and the variable i already has a value(the size of your collection).

Wrap your code inside a self executed function like this:

(function (i) {
  tab.addEventListener('click', function() { console.log(i); });
})(i);
katalin_2003
  • 787
  • 1
  • 16
  • 30
-3

Have you used JQUERY before? That might be an easier path. This way you can use $(".tab"). You can also use .forEach() instead of a for loop? Might make it more simple

Also, Paul's example seems to be working, can you provide a non working JSfiddle?