So within my Javascript I am able to duplicate my HTMl Id="characters" wrapper only once. I know it should technically be a "class" rather than an "Id" because it will be a duplicated "Id", but for some reason I don't get; when I change my "getElementById" to a "getElementsByClassName" and my HTML "Id" to a "class" it doesn't duplicate at all. Also because I am using clone.Node(true), I am losing the functionality of my "addEventListeners" in the duplicated wrapper. Is there a way to correct this using only vanilla Javascript? And as if this isn't annoying enough, my duplicated wrapper is throwing itself out of my CSS grid it seems. its all very tedious and troublesome, and so I thank you for any advice I can get.
Here is my current HTML.
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="css/style.css">
<h1><!--D&D DM Tool--><h1>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title></title>
</head>
<body>
<div id="header-container">
<h1 id="header">Game Tools</h1>
</div>
<div >
<button id="resetbutton">Next Round</button>
<button id="orderbutton">Order</button>
<button id="zerobutton">Zero</button>
<button id="deadremoverbtn">Bring Out the Dead!</button>
<button id="addnpcbtn">Add NPC</button>
</div>
<div id="grid">
<div >
<div id="subgrid" >
<div >
<div ></div>
<div >Name</div>
<button >Submit</button>
<input type="text" placeholder="Name">
<div class=int-stuf>
<div >Iniative</div>
<button >Submit</button>
<input type="number" placeholder="Iniative Roll">
</div>
<div >Healthpoints</div>
<button >Submit</button>
<input type="number" placeholder="Total HealthPoints">
<button >Submit</button>
<input type="number" placeholder="Damage">
</div>
<div >Weapons</div>
<button >Submit</button>
<input type="text" placeholder="Weapons">
<button >Active</button>
</div>
</div>
</div>
</body>
<script src="mainCopy.js"></script>
</html>
Here is my current Javascript duplication function.
addNpcBtn.addEventListener("click",function(){
var characterSubGrids=document.getElementsByClassName("characters");
console.log(characterSubGrids[0]);
var characterSubGridsClone=characterSubGrids[0].cloneNode(true);
let grid=document.getElementById("grid");
console.log(grid);
grid.appendChild(characterSubGridsClone);
});
CodePudding user response:
From the MDN article on cloneNode
Cloning a node copies all of its attributes and their values, including intrinsic (inline) listeners. It does not copy event listeners added using addEventListener() or those assigned to element properties (e.g., node.onclick = someFunction).
It seems like cloneNode
might already be ignoring the event listeners you're trying to ignore.
If you're trying to clone a <div>
in a way that conserves the event listeners on its <button>
children, I don't think the DOM has a method for that. Instead, you'll have to attach the same event listeners to the new cloned buttons. Something like the following:
// Fetch the container and save that element as a constant for future use
const container = document.querySelector('#container')
// Create the addHandlers function for future use
function addHandlers (span) {
// Find the first button child of the element provided as first parameter
const button = span.querySelector('button')
// Add a click event listener to that button
button.addEventListener('click', () => {
// On click, clone the parent element (the span, not the button)
const clone = span.cloneNode(true)
// Find the first input child of this new clone
const input = clone.querySelector('input')
// Set its value to the empty string (by default, the clone would conserve the value of the original)
input.value = ''
// Add handlers to the clone which were lost during cloning
addHandlers(clone)
// Add the clone into the DOM as a new, last child of the container
container.appendChild(clone)
}, false)
}
// Find all elements with class name 'duplicatable' and run the `addHandlers` function on each element
document.querySelectorAll('.duplicatable').forEach(addHandlers)
<div id="container">
<h2>Characters</h2>
<span >
<button>Add a new character</button>
<input type='text' placeholder='name' />
</span>
</div>