Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript classList.remove not working properly

Check this fiddle: JSFiddle

HTML:

<table class="myTable">
  <tr>
    <th>Some text</th>
    <td class="align">
      <span class=" someStyle">1</span>/<span class="otherStyle">15</span>
    </td>
    <th>Some text</th>
    <td class="align">
      <span class=" someStyle">2</span>/<span class="otherStyle">16</span>
    </td>
  </tr>
  <tr>
    <th>Some text</th>
    <td class="align">
      <span class="">3</span>/<span class="">17</span>
    </td>
    <th>Some text</th>
    <td class="align">
      <span class="otherStyle">4</span>/<span class=" someStyle">18</span>
    </td>
  </tr>
  <tr>
    <th>Some text</th>
    <td class="align">
      <span class="otherStyle">5</span>/<span class=" someStyle">19</span>
    </td>
    <th>Some text</th>
    <td class="align">
      <span class="">6</span>/<span class="">20</span>
    </td>
  </tr>
  <tr>
    <th>Some text</th>
    <td class="align">
      <span class="">7</span>/<span class="">21</span>
    </td>
    <th>Some text</th>
    <td class="align">
      <span class=" someStyle">8</span>/<span class="otherStyle">22</span>
    </td>
  </tr>
  <tr>
    <th>Some text</th>
    <td class="align">
      <span class="">9</span>/<span class="">23</span>
    </td>
    <th>Some text</th>
    <td class="align">
      <span class="otherStyle">10</span>/<span class=" someStyle">24</span>
    </td>
  </tr>
  <tr>
    <th>Some text</th>
    <td class="align">
      <span class="otherStyle">11</span>/<span class=" someStyle">25</span>
    </td>
    <th>Some text</th>
    <td class="align">
      <span class="otherStyle">12</span>/<span class=" someStyle">26</span>
    </td>
  </tr>
  <tr>
    <th>Some text</th>
    <td class="align">
      <span class=" someStyle">13</span>/<span class="otherStyle">27</span>
    </td>
    <th>Some text</th>
    <td class="align">
      <span class=" someStyle">14</span>/<span class="otherStyle">28</span>
    </td>
  </tr>
</table>

JavaScript:

var myTbl = document.getElementsByClassName("myTable")[0];

var tSomeStyleClasses = myTbl.getElementsByClassName("someStyle");
console.log(tSomeStyleClasses);
for (i=0;i<tSomeStyleClasses.length;i++) {
    console.log(tSomeStyleClasses[i].classList);
    //tSomeStyleClasses[i].classList.remove("someStyle");
}

var tOtherStyleClasses = myTbl.getElementsByClassName("otherStyle");
console.log(tOtherStyleClasses);
for (i=0;i<tOtherStyleClasses.length;i++) {
    console.log(tOtherStyleClasses[i].classList);
    //tOtherStyleClasses[i].classList.remove("otherStyle");
}

And check the console log. There are 10 entries for each, someStyle and otherStyle. Now uncomment //tSomeStyleClasses[i].classList.remove("someStyle"); and //tOtherStyleClasses[i].classList.remove("otherStyle"); and run the fiddle. Check the console log again. 2 x 10 styles should be removed, but instead it removes only 5 styles. I wonder why?

like image 990
Tomo Avatar asked Mar 05 '17 15:03

Tomo


People also ask

How do you clear a classList in JavaScript?

To remove all classes from an element, set the element's className property to an empty string, e.g. box. className = '' . Setting the element's className property to an empty string empties the element's class list.

How does classList work in JavaScript?

The Element.classList is a read-only property that returns a live DOMTokenList collection of the class attributes of the element. This can then be used to manipulate the class list. Using classList is a convenient alternative to accessing an element's list of classes as a space-delimited string via element.className .

Does classList return an array?

Does classList return an array? The className property returns the name of the classes in the form of a string, whereas the classList property of JavaScript returns the name of the classes in the form of an array.


2 Answers

The value returned from .getElementsByClassName() is a live NodeList. That it's "live" means that as you change the elements in the list, the list itself automatically updates. Thus, when you remove the class that you used to find the elements, the list gets shorter. Because you're iterating with a numeric index, you end up skipping elements.

A good way to deal with that is to use a simple while loop and operate only on the first element of the list until the list is empty:

var tSomeStyleClasses = myTbl.getElementsByClassName("someStyle");

while (tSomeStyleClasses.length) {
    tSomeStyleClasses[0].classList.remove("someStyle");
}
like image 85
Pointy Avatar answered Oct 28 '22 16:10

Pointy


Because getElementsByClassName gives you a live list of matching elements. When you remove the class from the element at index 0, the list is updated immediately to remove that element from the list and shuffle all the others down. Since you then increment i, the element now at index 0 doesn't get processed.

Either:

  1. Work your way through the list backward, or

  2. Use document.querySelectorAll(".someStyle"), which returns a snapshot list, not a live one

like image 25
T.J. Crowder Avatar answered Oct 28 '22 16:10

T.J. Crowder