Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

addEventListener on a querySelectorAll() with classList

I am trying to add an event listener but no result came. I know JavaScript has a hoisting feature but I believe I tried all except the correct solution.

const cbox = document.querySelectorAll(".box");
function doit() {
  for (let i = 0; i < cbox.length; i++){
    cbox[i].classList.add("red");
  }
}
cbox.addEventListener("click", doit, false);

Can somebody spot the mistake I make?

like image 702
Evan Avatar asked Jun 01 '18 12:06

Evan


People also ask

Does addEventListener work with querySelectorAll?

To add an event listener to the results from the querySelectorAll method: Use the forEach() method to iterate over the collection of elements. Call the addEventListener() method on each element in the collection.

What does the querySelectorAll () method do?

The querySelectorAll() method in HTML is used to return a collection of an element's child elements that match a specified CSS selector(s), as a static NodeList object. The NodeList object represents a collection of nodes. The nodes can be accessed by index numbers. The index starts at 0.


3 Answers

There are some dissimilarities between the code and the link you have provided. There is no function doit() in there.

You have attached addEvenListener to the NodeList in cbox.addEventListener("click",....., you have to loop through the list and attach the event to the current element:

Try the following:

const cbox = document.querySelectorAll(".box");

 for (let i = 0; i < cbox.length; i++) {
     cbox[i].addEventListener("click", function() {
       cbox[i].classList.toggle("red");
     });
 }
*,
html,
body {
    padding: 0;
    margin: 0;
}

.box {
    width: 10rem;
    height: 10rem;
    background-color: yellowgreen;
    float: left;
    position: relative;
    margin: 0.5rem;
    transition: .5s all;
}

h3 {
    display: block;
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
}

.box:not(:first-child) {
    margin-left: 1rem;
}

.red {
    background-color: orangered;
}
<div id="box1" class="box box1">
    <h3>Box 1</h3>
</div>
<div id="box2" class="box box2">
    <h3>Box 2</h3>
</div>
<div id="box3" class="box box3">
    <h3>Box 3</h3>
</div>
<div id="box4" class="box box4">
    <h3>Box 4</h3>
</div>

You can also use Array.prototype.forEach() with arrow function syntax that will allow you to achieve the same with less code:

let cbox = document.querySelectorAll(".box");
cbox.forEach(box => {
  box.addEventListener('click', () => box.classList.toggle("red"));
});
*,
html,
body {
    padding: 0;
    margin: 0;
}

.box {
    width: 10rem;
    height: 10rem;
    background-color: yellowgreen;
    float: left;
    position: relative;
    margin: 0.5rem;
    transition: .5s all;
}

h3 {
    display: block;
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
}

.box:not(:first-child) {
    margin-left: 1rem;
}

.red {
    background-color: orangered;
}
<div id="box1" class="box box1">
    <h3>Box 1</h3>
</div>
<div id="box2" class="box box2">
    <h3>Box 2</h3>
</div>
<div id="box3" class="box box3">
    <h3>Box 3</h3>
</div>
<div id="box4" class="box box4">
    <h3>Box 4</h3>
</div>
like image 192
Mamun Avatar answered Oct 09 '22 18:10

Mamun


ES6 makes this a bit simpler:

document.querySelectorAll(".box").forEach(box => 
  box.addEventListener("click", () => box.classList.toggle("red"))
)

Example implementation:

document.querySelectorAll(".box").forEach(box =>
  box.addEventListener("click", () => box.classList.toggle("red"))
)
.box {
  width: 5rem;
  height: 5rem;
  background-color: yellowgreen;
  display: inline-block;
}

.box.red {
  background-color: firebrick;
}
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
like image 38
leonheess Avatar answered Oct 09 '22 18:10

leonheess


You can use forEach on the class or use Event delegation.

const cboxes = document.querySelectorAll(".box");
function doit() {
    ... do something ...
}
cboxes.forEach(
  function(cbox) {
   cbox.addEventListener("click", doit,false);
  }
);

Notice that I changed your variable name.

EventDelgation

HTML:

<div id="parent">
  <div id="box1" class="box box1">
    <h3>Box 1</h3>
  </div>
  <div id="box2" class="box box2">
      <h3>Box 2</h3>
  </div>
  <div id="box3" class="box box3">
      <h3>Box 3</h3>
  </div>
  <div id="box4" class="box box4">
      <h3>Box 4</h3>
  </div>
</div>

The JS part:

const parent = document.querySelector("#parent");

parent.addEventListener('click', (e) => {
  e.target.classList.add('red');
  console.log(e.target);
});

Event delegation is much better and it uses fewer resources, as you only use 1 Event listener and no for loop.

like image 14
Riad ZT Avatar answered Oct 09 '22 17:10

Riad ZT