Home > Enterprise >  forEach eventListener iteration increases every time the function is called
forEach eventListener iteration increases every time the function is called

Time:09-23

I'm creating a simple etch-a-sketch that colors the created squares on a click and drag event.

When you run below code please note that in the very beginning, every div.square that is being catched by eventListener returns exactly one div.square and I consider this as a normal behaviour.

Now, every time you click on a "Rainbow mode" button a function listening('rainbow') is being called and now a single div.square is being returned twice (I added a console.log to catch it). When you press "Rainbow mode" again a single div.square will be called 3 times and it increases in this manner.

Why is it happening? Why when I run a debugger I can see that eventListener section of listening() function is being iterated several times and the number of iterations increases every time listening() function is being called?

const board = document.querySelector('#board');
let color = 'black';

function createSquares(squareSize) { 
    squareSize = (480/squareSize);
    for (i=0; i<Math.pow((480/squareSize), 2); i  ) {
    const square = document.createElement('div');
    square.classList.add('square');
    square.style.cssText = `
        width: ${squareSize}px;
        height: ${squareSize}px;
        background-color: transparent;`; 
    board.appendChild(square);
};
}

function listening(color) {

    if (color === 'rainbow') { 
        console.log("rainbow selected"); 
        const squaresAll = document.querySelectorAll('div.square');
        squaresAll.forEach((square) => {
        square.addEventListener('mouseover', (e) => {
            if (e.buttons === 1 || e.buttons === 3) {
                console.log(e.currentTarget);
                        let rainbowColor = "#"   ((1<<24)*Math.random() | 0).toString(16);
                        e.currentTarget.style.backgroundColor = rainbowColor;
                        return;
        }
        
    })
})
    }
    else {
        console.log("other color selected");
        const squaresAll = document.querySelectorAll('div.square');
        squaresAll.forEach((square) => {
        square.addEventListener('mouseover', (e) => {
            if (e.buttons == 1 || e.buttons == 3) {
                        console.log(e.currentTarget);
                        e.target.style.backgroundColor = color;
        }
    })
})

    }
}

function resetBoard() {
    const squaresAll = document.querySelectorAll('div.square');
    squaresAll.forEach((square) => {
        square.style.backgroundColor = 'transparent';
    })
}

const selectSizeButton = document.querySelector('#selectSizeButton');
selectSizeButton.addEventListener(('click'), () => {
    let squareSize = prompt(`Enter the number of squares per side of a grid`, "50");
    const squaresAll = document.querySelectorAll('div.square');
    squaresAll.forEach((square) => {
        square.remove();
    });
    createSquares(squareSize);
})

const resetButton = document.querySelector('#resetButton');
resetButton.addEventListener(('click'), resetBoard);

const rainbowButton = document.querySelector('#rainbowButton');
rainbowButton.addEventListener(('click'), function() { listening('rainbow');});

createSquares(30);
listening(color);
body {
    margin: 0 auto;
    display: flex;
    justify-content: flex-start;
    align-items: center;
    width: 100vw;
    height: 100vh;
    flex-direction: column;
}

.controls {
    width: 480px;
    height: 50px;
    flex: 0 0 auto;
    background-color: aquamarine; /*to be deleted*/
    margin-top: 10vh;
    margin-bottom: 5vh;
    display: flex;
    align-items: center;
    justify-content: center;
}

#board {
    width: 480px;
    height: 480px;
    flex: 0 0 auto;
    background-color:#f5f0ff;
    display: flex;
    flex-flow: row wrap;
    margin: 0;
    padding: 0;
}

.square {
    border-color:#d7d3e1;
    border-style: solid;
    box-sizing: border-box;
    border-width: 1px;
    padding: 0;
    margin: 0;
    flex: 0 0 auto;
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Etch-a-Sketch</title>
    <script src="./script.js" defer></script>
    <link rel="stylesheet" href="./style.css">
</head>
<body>
    <div >
        <button id="selectSizeButton">Change size</button>
        <button id="resetButton">Reset</button>
        <button id="rainbowButton">Rainbow mode</button>
    </div>
    <div id="board">

    </div>
</body>
</html>

CodePudding user response:

You have addEventListener inside an event listener - every time you click, you add another listener

Please delegate, it makes everything so much simplerr

const board = document.getElementById('board');
const controls = document.querySelector('.controls');
let color = 'black';
let rainbow = false;
controls.addEventListener("click", function(e) {
  const tgt = e.target;
  if (tgt.matches("#selectSizeButton")) {
    let squareSize = prompt(`Enter the number of squares per side of a grid`, "50");
    const squaresAll = document.querySelectorAll('div.square');
    squaresAll.forEach((square) => {
      square.remove();
    });
    createSquares(squareSize);

  } else if (tgt.matches("#resetButton")) {
    board.querySelectorAll(".square").forEach((square) => {
      square.style.backgroundColor = 'transparent';
    })
  } else if (tgt.matches("#rainbowButton")) {
    rainbow = !rainbow;
    if (rainbow) {
      console.log("rainbow selected");
    } else {
      console.log("other color selected");
    }
  }
})

board.addEventListener("mouseover", function(e) {
  const tgt = e.target;
  if (e.buttons === 1 || e.buttons === 3) {
    //console.log(e.currentTarget);
    color = rainbow ? "#"   ((1 << 24) * Math.random() | 0).toString(16) : color;
    tgt.style.backgroundColor = color;
  }
})

const createSquares = squareSize => {
  squareSize = (480 / squareSize);
  console.log(squareSize ); 
  for (i = 0; i < Math.pow((480 / squareSize), 2); i  ) {
    const square = document.createElement('div');
    square.classList.add('square');
    square.style.cssText = `
        width: ${squareSize}px;
        height: ${squareSize}px;
        background-color: transparent;`;
    board.appendChild(square);
  };
};
createSquares(10);
body {
  margin: 0 auto;
  display: flex;
  justify-content: flex-start;
  align-items: center;
  width: 100vw;
  height: 100vh;
  flex-direction: column;
}

.controls {
  width: 480px;
  height: 50px;
  flex: 0 0 auto;
  background-color: aquamarine;
  /*to be deleted*/
  margin-top: 10vh;
  margin-bottom: 5vh;
  display: flex;
  align-items: center;
  justify-content: center;
}

#board {
  width: 480px;
  height: 480px;
  flex: 0 0 auto;
  background-color: #f5f0ff;
  display: flex;
  flex-flow: row wrap;
  margin: 0;
  padding: 0;
}

.square {
  border-color: #d7d3e1;
  border-style: solid;
  box-sizing: border-box;
  border-width: 1px;
  padding: 0;
  margin: 0;
  flex: 0 0 auto;
}
<div >
  <button id="selectSizeButton">Change size</button>
  <button id="resetButton">Reset</button>
  <button id="rainbowButton">Rainbow mode</button>
</div>
<div id="board">

</div>

  • Related