-2

Adding an HTML element to the body or a parent div using the += operator clears the event listeners.

The following is the code I wrote to investigate this issue. The overall result is losing the event listeners when adding the last HTML element. However, it is interesting that when adding an HTML element to the body, it clears all previous event listeners, but when we add an HTML element to the div (id = parent), it clears the event listeners of the siblings but not the body.

How can we append HTML to a specific element without unpredictably losing event listeners anywhere?

document.getElementById('button1').addEventListener('click', e => {
  document.getElementById('message').innerHTML = `<h3>You clicked button 1</h3>`
})

document.getElementById('button2').addEventListener('click', e => {
  document.getElementById('message').innerHTML = `<h3>You clicked button 2</h3>`
})

document.getElementById('addToBody').addEventListener('click', e => {
  document.body.innerHTML += '<button id="button3">No. 3 Element in Body</button>'
  document.getElementById('button3').addEventListener('click', e => {
    document.getElementById('message').innerHTML = `<h3>You clicked button 3</h3>`
  })
  document.getElementById('message').innerHTML = `<h3>You added an element to the body</h3>`
})

document.getElementById('addToParent').addEventListener('click', e => {

  document.getElementById('parent').innerHTML += '<button id="button4">No. 4 Element in Parent Div</button>'
  document.getElementById('button4').addEventListener('click', e => {
    document.getElementById('message').innerHTML = `<h3>You clicked button 4 Parent Div</h3>`
  })
  document.getElementById('message').innerHTML = `<h3>You added an element to the Parent</h3>`

})

document.getElementById('addToBody2').addEventListener('click', e => {

  document.body.innerHTML += '<button id="button5">No. 4 Element in Parent Div</button>'
  document.getElementById('button5').addEventListener('click', e => {
    document.getElementById('message').innerHTML = `<h3>You clicked button 5 </h3>`
  })
  document.getElementById('message').innerHTML = `<h3>You added a 2nd element to the body</h3>`
})
<body>
  <div id="parent">
    <button id="button1">No. 1</button>
    <button id="button2">No. 2</button>
  </div>

  <button id="addToBody">Add an Element to the Body</button>
  <button id="addToParent">Add a Sibbling to the Parent Div with ID of parent</button>
  <button id="addToBody2">Add a 2nd Element to the Body</button>

  <div id="message"></div>
</body>
EricandWeb
  • 25
  • 6
  • 3
    Well, overwriting the HTML is overwriting the HTML. That's what the innerHTML method does. Why aren't you simply appending elements to the parent with `append()`? – isherwood Oct 27 '22 at 20:40
  • Which eventListener(s) specifically are being cleared? Have you tried creating the elements with `document.CreateElement()` and appending, vs adding html via innerHTML? – mykaf Oct 27 '22 at 20:41
  • The code I posted is specifically designed to answer the questions about which event listeners we lose and when. – EricandWeb Oct 27 '22 at 20:43
  • Does this answer your question? [Append HTML to container element without innerHTML](https://stackoverflow.com/q/6304453/1264804) – isherwood Oct 27 '22 at 20:46
  • element.innerHTML = "

    New Element

    overrides whatever in the element, but element.innerHTML += "

    Element to append

    does not override. However, it messes with the existing event listeners.
    – EricandWeb Oct 27 '22 at 20:46
  • The evidence would indicate otherwise. – isherwood Oct 27 '22 at 20:47
  • I am investigating append() and createElement(), however, element.innerHTML += ' new HTML' seems to be very popular. I want to know if I am missing something obvious about the use of the += operator. – EricandWeb Oct 27 '22 at 20:49

1 Answers1

0

As mentioned in the comments - when you rewrite the html element (i.e. you recreate buttons and such inside of an element) you are going to lose your bindings to those elements that get recreated.

If you feel you need to stick with the way you're rewriting elements, then you'll want to change the way you're binding to the elements - you'll want to bind a click event to something higher up in the hierarchy of the DOM and then check each click to match the elements you want to react to, like so:

document.body.addEventListener('click', function(e){
    console.log(e.target);
    if(e.target.getAttribute('data-a-target') === "popout-chat-button"){
        console.log('popout button');
    }
});

This answer is from another stackoverflow question: https://stackoverflow.com/a/49956060/1075723

brobert7
  • 49
  • 1