3

I dynamically create a checkbox that has an EventListener. Unfortunately the EventListener doesn't work if I change the text of the checkbox-label with innerHTML:

let label = document.createElement('label'),
    input = document.createElement('input');
input.setAttribute('type', 'checkbox');
input.addEventListener('change', () => alert('Change Detected'));

label.appendChild(input);
document.body.appendChild(label);
label.innerHTML += 'Select Me!';

How can I circumvent this problem and why does it even exist?

Here a working snippet without the innerHTML:

let label = document.createElement('label'),
    input = document.createElement('input');
input.setAttribute('type', 'checkbox');
input.addEventListener('change', () => alert('Change Detected'));

label.appendChild(input);
document.body.appendChild(label);
leonheess
  • 16,068
  • 14
  • 77
  • 112

1 Answers1

6

When you concatenate to the innerHTML of an element, its contents are cleared, the existing HTML string is concatenated with the new string, and then the container's contents are re-calculated according to the new HTML string. ~~Listeners~~ Elements attached to elements previously in the container do not survive the serialization process - the children of the container after changing innerHTML are new.

Append a text node instead:

let label = document.createElement('label');
let input = document.createElement('input');
input.setAttribute('type', 'checkbox');
input.addEventListener('change', () => alert('Change Detected'));

label.appendChild(input);
document.body.appendChild(label);
label.appendChild(document.createTextNode('Select Me!'));

Or use insertAdjacentHTML:

let label = document.createElement('label');
let input = document.createElement('input');
input.setAttribute('type', 'checkbox');
input.addEventListener('change', () => alert('Change Detected'));

label.appendChild(input);
document.body.appendChild(label);
label.insertAdjacentHTML('beforeend', 'Select Me!');
leonheess
  • 16,068
  • 14
  • 77
  • 112
CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
  • 1
    It's completely up to you. I don't really have an opinion, they both work just fine. If you're inserting non-trivial markup, it's probably nicer to use `insertAdjacentHTML` because that way the new HTML structure is clearer (when you can see the markup directly, rather than having to parse through the `createElement`s and `appendChild`s to see what's connected to what) – CertainPerformance May 06 '19 at 07:34
  • 1
    "Listeners attached to elements previously in the container do not survive the serialization process." that's not what happens no. `input` has been removed from the DOM, hence, the one `` you have here is not the previous `input` one. And this one doesn't have any event attached to it. But the Event Listener is still very alive (for as long as the GC collects `input`). https://jsfiddle.net/bqvgmxLd/ – Kaiido May 06 '19 at 07:34