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>