I am creating a Javascript framework recently and I am facing two problems that I don't understand at all. When I create a new button with createElement()
in Javascript, I can't place it inside several elements at the same time without killing the "click" event (if this is an id
, it works).
(Note : "button.onclick = function()"
doesn't work either)
Here is the code : (I don't want to use any libraries)
function createButton() {
var button = document.createElement("button");
button.innerHTML = "YOOOO";
button.style.backgroundColor = "red";
button.style.color = "white";
// Problem Two : If I click on the button, nothing happends
button.addEventListener("click", function(e) {
alert(e.target);
}, false);
var clas = document.getElementsByClassName("test");
Array.from(clas).forEach(element => {
element.appendChild(button);
element.innerHTML += ""; // First problem : If I don't do this, the button does not appear in the first div. I have no idea why !
});
}
createButton();
body {
margin: 0;
padding: 0;
display:flex;
justify-content: center;
align-items: center;
height: 100vh;
background-color: rgba(30, 30, 30, 0.2);
}
button {
cursor: pointer;
width: 80px;
height: 50px;
padding: 10px;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>bug</title>
</head>
<body>
<div class="test" id="1" style="padding: 50px;">
<span>1</span>
</div>
<div class="test" id="2" style="padding: 50px;">
<span>2</span>
</div>
</body>
</html>
There are 2 problems:
element.innerHTML += "";
, where element
refers to the button's parent, will force the parent to re-parse its contents from their HTML string, thus corrupting any existing handlers on child elements. The element the listener is attached to will be removed from the DOM and replaced with a different one; the new one does not have the listener.
When you do appendChild
, if the element being appended already exists in the DOM, it'll be removed from where it existed previously before being appended to its new location. Since you only do document.createElement('button')
once, without the innerHTML += ''
, the button gets removed from its first position when appended to the second.
Create the button inside the loop instead, and both problems are solved.
function createButton() {
var clas = document.getElementsByClassName("test");
Array.from(clas).forEach(element => {
var button = document.createElement("button");
button.innerHTML = "YOOOO";
button.style.backgroundColor = "red";
button.style.color = "white";
// Problem Two : If I click on the button, nothing happends
button.addEventListener("click", function(e) {
alert(e.target);
}, false);
element.appendChild(button);
});
}
createButton();
body {
margin: 0;
padding: 0;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background-color: rgba(30, 30, 30, 0.2);
}
button {
cursor: pointer;
width: 80px;
height: 50px;
padding: 10px;
}
<div class="test" id="1" style="padding: 50px;">
<span>1</span>
</div>
<div class="test" id="2" style="padding: 50px;">
<span>2</span>
</div>
Or, making the code a bit prettier:
function createButton() {
for (const parent of document.querySelectorAll('.test')) {
const button = parent.appendChild(document.createElement("button"));
button.textContent = "YOOOO";
button.style.backgroundColor = "red";
button.style.color = "white";
button.addEventListener("click", function(e) {
console.log(e.target);
});
}
}
createButton();
body {
margin: 0;
padding: 0;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background-color: rgba(30, 30, 30, 0.2);
}
button {
cursor: pointer;
width: 80px;
height: 50px;
padding: 10px;
}
<div class="test" id="1" style="padding: 50px;">
<span>1</span>
</div>
<div class="test" id="2" style="padding: 50px;">
<span>2</span>
</div>