Search code examples
javascripthtmladdeventlistenerinnerhtmlevent-listener

Event​Target​.add​Event​Listener() not working after innerHTML


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);


Solution

  • 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!');