I am trying to altar the background color of dynamically generated div elements on a mouseover event. I am still new to event listeners and feel I am lacking a fundamental concept on how they work. How do I get them to apply to elements created after the DOM has loaded?
const divSelector = document.querySelectorAll('main.child')
let gridSize = gridMaker();
let gridHover = colorChange();
function gridMaker () {
let size = prompt('Enter a size: ')
for (let i = 0; i < size; i++) {
var div = document.createElement("div");
div.style.width = "100px";
div.style.height = "100px";
div.style.background = "red";
div.style.margin = '10px';
div.id = 'etch';
document.getElementById("main").appendChild(div);
}
}
//When mouse hovers over a div, permanently change color of that div
function colorChange () {
divSelector.forEach((e) => {
document.body.addEventListener('mouseover', (e) => {
if (e.target.id == 'etch') {
console.log('target found')
}
});
})
}
<!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="./app.js" defer></script>
</head>
<body>
<div id="main">
</div>
</body>
</html>
3
Answers
You can attach an event listener directly to div when you create it and add your logic to the callback.
The statement
const divSelector = document.querySelectorAll('main.child');
is run at the start of the script, at which point, there are no<main>
elements with theclass
ofchild
in the page. This means thatdivSelector
will be an emptyNodeList
. So whencolorChange()
is called as the third statement, thedivSelector.forEach()
runs over an empty list and so the callback function is never run.You shouldn’t need the aforementioned
const divSelector = document.querySelectorAll('main.child');
statement or its later.forEach()
call if you are going to be listening tomouseover
on thedocument
:First, the problems with your existing code:
Now, to address those problems you can either use event-binding at the point of element-creation, or you can use event-delegation. First, event-binding at the point of creation:
Next, event-binding; in which we bind the event-handler, as you were trying to do, to the existing ancestor element of those you wish to act upon:
JS Fiddle demo.
References:
Array.from()
.Array.prototype.forEach()
.CSSStyleDeclaration.cssText
.document.createDocumentFragment()
.document.createElement()
.document.querySelector()
.document.querySelectorAll()
.Element.classList
API.EventTarget.addEventListener()
.HTMLElement.style
.Node.cloneNode()
.parseInt()
.String.prototype.trim()
.window.prompt()
.