Reputation: 877
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>
Upvotes: 0
Views: 2677
Reputation: 178413
I strongly suggest you delegate and clone
I think I already posted this answer for you a few days ago
function createButton() {
const button = document.createElement("button");
button.classList.add("redwhite");
button.innerHTML = "YOOOO";
[...document.querySelectorAll(".test")].forEach(element => {
element.appendChild(button.cloneNode(true));
});
}
createButton();
document.getElementById("container").addEventListener("click", function(e) {
const tgt = e.target;
if (tgt.classList.contains("redwhite")) {
console.log(tgt.closest("div").id)
}
})
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;
}
.redwhite {
background-color: red;
color: white;
}
<div id="container">
<div class="test" id="1" style="padding: 50px;">
<span>1</span>
</div>
<div class="test" id="2" style="padding: 50px;">
<span>2</span>
</div>
</div>
Upvotes: 0
Reputation: 56813
Your button is a single instance, and repeatedly calling
element.appendChild(button);
just moves it in the DOM repeatedly.
Your subsequent call to
element.innerHTML += "";
removes that reference from the DOM and instead creates a new button
from its outerHTML
. That is also where your added event listener gets lost.
If you need more than one button, your also need to create more than one button.
Upvotes: 0
Reputation: 371168
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>
Upvotes: 3