I need to clone a div that contains an input file, and within the clone, there is a button to delete the created clone.
My problem is that once the clone is created I cannot add the function on the button to delete the clone.
The function does not work. Where am I wrong?
if (document.querySelector('.clona-input-file') !== null) {
var clonaInputFile = document.querySelector('.clona-input-file');
clonaInputFile.addEventListener('click', function(e) {
e.preventDefault();
var RowDaClonare = document.querySelector('#row-da-clonare');
var clone = RowDaClonare.cloneNode(true);
clone.children[0].lastElementChild.value = '';
clone.id = 'row-da-clonare-' + Date.now();
RowDaClonare.after(clone);
var _buttonDel = document.createElement("button");
_buttonDel.id = 'cancellaInputClone';
_buttonDel.type = 'button';
_buttonDel.setAttribute("data-id-da-eliminare", clone.id);
_buttonDel.classList.add("btn");
_buttonDel.classList.add("btn-danger");
_buttonDel.classList.add("cancellaInputClone");
_buttonDel.innerHTML = '<i class="bi bi-trash-fill"></i>';
clone.appendChild(_buttonDel);
});
}
var cloneSet = document.querySelectorAll(".cancellaInputClone");
for (var i = 0; i < cloneSet.length; i++) {
cloneSet[i].addEventListener('click', fx_button);
}
function fx_button() {
console.log(this)
}
>Solution :
The issue is because you’re attempting to bind event handlers to elements which don’t yet exist in the DOM. This can be addressed by delegating your event handlers to parent elements which do exist when the DOM loads, and interrogating the events to see if they were raised by the elements you created.
In addition there’s some other issues in your code to address:
Firstly, don’t use id attributes in dynamic content. It makes your logic more complex than it needs to be. Use classes instead, and relate elements to each other using DOM traversal methods, such as closest().
Secondly, use querySelector() to find the child element, not children/index accessors. It’s more robust.
Lastly, you can provide multiple separate class names to classList.add() to save you having to call it repeatedly.
With that said, try this working example:
let cloneButton = document.querySelector('.clona-input-file');
if (cloneButton) {
cloneButton.addEventListener('click', function(e) {
e.preventDefault();
let rowDaClonare = document.querySelector('.row-da-clonare'); // querySelector will return first match only
let clone = rowDaClonare.cloneNode(true);
clone.querySelector('input').value = '';
rowDaClonare.after(clone);
let buttonDel = document.createElement("button");
buttonDel.type = 'button';
buttonDel.classList.add("btn", "btn-danger", "cancellaInputClone");
clone.appendChild(buttonDel);
let icon = document.createElement('i');
icon.classList.add('bi', 'bi-trash-fill');
buttonDel.appendChild(icon);
});
}
// icon click handler delegated to the .container element
document.querySelector('.container').addEventListener('click', e => {
let el = e.target;
if (!el.classList.contains('cancellaInputClone') && !el.closest('button')?.classList.contains('cancellaInputClone'))
return;
el.closest('.row-da-clonare').remove();
});
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.3.0/font/bootstrap-icons.css">
<div class="container">
<button class="clona-input-file">Clone</button>
<div class="row-da-clonare">
<div>
Lorem ipsum dolor sit.
<input type="text" class="foo" />
</div>
</div>
</div>