Home > Mobile >  modifying elements of getElementsByClass results in NaN
modifying elements of getElementsByClass results in NaN

Time:07-13

I am running into trouble with this script below, as I take a collection based on a class name and then modify the class names of each member of the collection respectively the programs triggers that the very items of the collection are undefined.

I assume this has to do with the collection falling apart as I remove what made the elements belong to the collection? Could you give me a hint to how I could implement smth like this?

<script>
        var toggle1 = document.getElementById("toggle1");
        toggle1.addEventListener("click", Colortoggle);
    
        function Colortoggle() {
            if (toggle1.className === " white") {
                var collection = document.getElementsByClassName("white");
                for (let i = 0; i < collection.length; i  ) {
                    collection[i].className -= "white";
                    collection[i].className  = "black";
                }
            } else {
                var collection = document.getElementsByClassName("black");
                for (let i = 0; i < collection.length; i  ) {
                    collection[i].className -= "black";
                    collection[i].className  = "white";
                }
            }
            console.log("colortoggle was finished");
        }
        
    </script>

These are the classes in the beginning: enter image description here

This is the change in classes: enter image description here

CodePudding user response:

  • The main logic for below code is toggle1.classList.contains("white") this statement return true if toggle has class white else return false.

  • WIth DOM elements you can use this classList methods classList.add(),classList.remove().

  • classList.add() => this will add class to selected DOM element.

  • classList.remove() => this will remove class to selected DOM element.

  • for more information abslout classList method please visit this.

var toggle1 = document.querySelector("#toggle1");
toggle1.addEventListener("click", Colortoggle);

function Colortoggle() {
  if (toggle1.classList.contains("white")) {
    var collection = document.querySelectorAll(".white");
    collection.forEach(element => {
      element.classList.add("black");
      element.classList.remove("white");
    })
  } else {
    var collection = document.querySelectorAll(".black");
    collection.forEach(element => {
      element.classList.add("white");
      element.classList.remove("black");
    })
  }
  console.log("colortoggle was finished");
}
.main div {
  display: inline-block;
  height: 100px;
  width: 100px;
}

.white {
  background-color: #f0f0f0;
  color: black;
}

.black {
  background-color: #000000;
  color: white;
}
<div >
  <div id="toggle1" >toggle1 click here</div>
  <div ></div>
  <div ></div>
  <div ></div>
  <div ></div>
</div>

CodePudding user response:

In JavaScript, the subtraction operator (-) does not work with non-numbers; that is why it yields NaN. If you want to edit the class name of an element, please use methods like add(), remove(). For more information, please see here.

CodePudding user response:

As a sidenote: getElementsByClassName() returns a live HTMLCollection, which means you should never iterate over it using a for-loop while also modifying elements such as that they get removed from the collection.

Lets picture this:

Let this be the collection getElementsByClassName('foo'), with -> displaying the current iteration of the loop.

// list before iterating
    0: <div >0</div>
    1: <div >1</div>
    2: <div >2</div>

// first iteration i=0
 -> 0: <div >0</div> // in this iteration, remove .foo
    1: <div >1</div>
    2: <div >2</div>

// still first iteration, but now collection[0] is actually what was collection[1] before
 -> 0: <div >1</div>
    1: <div >2</div>

// second iteration i=1
    0: <div >1</div> // we never touch this one!!
 -> 1: <div >2</div>

You will not have this problem if instead of getElementsByClassName('foo') you work with querySelectorAll('.foo').

Second sidenote: No, this cannot be fixed using for (const div of divs) instead, as it internally seems to work with indexes as well.

  • Related