2

I attached a codepen example : http://codepen.io/anon/pen/zpmjJ

I just try to change the classname of an html collection array with a classic loop and after many test i can't figure out whats wrong and if i made a common mistake, i have always one item ignored.

<div class="test">1</div>
<div class="test">2</div>
<div class="test">3</div>

bout.addEventListener("click",function(){

   var newtest = document.getElementsByClassName('test');
     for (i=0; i < newtest.length; i++)
     {
         newtest[i].className="bob";
     }

 });
albator
  • 859
  • 1
  • 10
  • 18
  • possible duplicate of [How can I replace one class with another on all elements, using just the DOM?](http://stackoverflow.com/questions/16510973/how-can-i-replace-one-class-with-another-on-all-elements-using-just-the-dom) – Anonymous Jun 18 '15 at 15:09

2 Answers2

3

The problem here is that you are using document.getElementsByClassName which gives you a live NodeList. You should use document.querySelectorAll('.test') instead.

var newtest = document.querySelectorAll('.test');
for (var i=0; i < newtest.length; i++) {
    newtest[i].className = "bob";
}

With live NodeList collection newtest is a reference to a dynamically updated collection of elements (indexed by className test). So after the first loop iteration when you overwrite className with bob the whole collection becomes smaller by one (because newtest[0] no longer has class test). It makes indices shift.

One more problem with your code: don't forget var keywords.

Demo: http://codepen.io/anon/pen/BAFyb

dfsq
  • 191,768
  • 25
  • 236
  • 258
1

getElementsByClassName is live selector, so when you change something that not matching this selector, it will remove element from scope. So at first iteration it has 3 elements, but when you change class, it remove one element and you leave with 2 elements, so on next iteration it will take i element which is i=1 so it will take second element from top. That's why you get always 1 missing. You may use newtest[0].className="bob"; to loop through, but when you will reach last element, it will be single element, not array any more, so you need to use newtest.className="bob"; for last one

monkeyinsight
  • 4,719
  • 1
  • 20
  • 28
  • thx,oh i see, getElementsByClassName seems faster by far than querySelectorAll in all jsperf test but for dom manipulation in loop, querySelectorAll is the best way to do it thats right? – albator Oct 21 '14 at 05:30
  • @albator yes, `querySelector` is more flexible – monkeyinsight Oct 21 '14 at 05:31