Onclick button is working only in first list

Viewed 156

I want to duplicate list item with all its child elements, here is the my sample code. only in first list, on click is working, duplicated list's button is not working

document.querySelectorAll(".btnMe").forEach(el => {
  el.addEventListener('click', () => {
    var myDiv = document.querySelector(".list");
    var divClone = myDiv.cloneNode(true);
    document.querySelector('#lists').appendChild(divClone);
  })
})
<ul id="lists">
  <li class="list">
    <p>Test</p>
    <button class="btnMe">Click Me</button>
  </li>
</ul>

2 Answers

Instead of dealing with binding events, use event delegation.

var wrapper = document.querySelector("#lists")
wrapper.addEventListener('click', (evt) => {
  var btnClicked = evt.target.closest("button.btnMe");
  if (btnClicked) {
    var myDiv = document.querySelector(".list");
    var divClone = myDiv.cloneNode(true);
    wrapper.appendChild(divClone);
  }
})
<ul id="lists">
  <li class="list">
    <p>Test</p>
    <button class="btnMe">Click Me</button>
  </li>
</ul>

cloneNode copies all of the node's attributes and values but not their event listeners added using addEventListener(). So you need to add these event listeners again.

Your document.querySelectorAll() runs only the first time you load the page so a simple document.querySelector() should work and in that case you don't even need the forEach() method.

If I understand correctly, you want to clone the element the button you clicked is in. If the button is the child of the li, then you can clone node.parentNode. After you cloned it, you can add the event listener function to it.

function cloneParent() {
    let clone = this.parentNode.cloneNode(true);

    clone.querySelector('.btnMe').addEventListener('click', cloneParent);
    document.querySelector('#lists').appendChild(clone);
}    

document.querySelector('.btnMe').addEventListener('click', cloneParent);
<ul id="lists">
  <li class="list">
    <p>Test</p>
    <button class="btnMe">Click Me</button>
  </li>
</ul>

Adding only one event listener and using event delegation, as @epascarello described, should be the preferred way.

Related