Why Your Event Listeners Only Apply to the Last List Element

Content:

When building a UI, it’s common to loop over elements and append them to your HTML.

for (i = 0; i < length; i++) {
    parent.innerHTML += '<button id="button-' + i + '>' + text + '</button>';
}

When using buttons or link tags, you’re also likely to want to add an event listener, to handle the onclick event.

for (i = 0; i < length; i++) {
    parent.innerHTML += '<button id="button-' + i + '>' + text + '</button>';

    const buttonElement = parent.querySelector('#button-' + i);
    buttonElement.onclick = (() => {
        ...
    });
}

This looks like it should work as intended. For each element, the parent innerHTML is updated to add a new HTML button element, and a new onclick event listener is attached to the button.

Running the code, however, you’ll find that only the last element in the loop has an event listener attached.

This is a simple issue to fix, but only once you’re aware of the cause.

Altering the innerHTML property of the parent element directly causes all event listeners currently attached to to be removed.

The fix it to alter the code to avoid altering the innerHTML property of the parent element.

The easiest way to do this is to use the insertAdjacentHTML function. This function allows HTML to be added to the element, in the position specified.

parent.insertHTML(position, html);

Valid values for position are as follows:

  • beforebegin: Inserts content before the element opening tag
  • afterbegin: Inserts content after the element opening tag, but before existing content.
  • beforeend: Inserts content after the content currently inside the element
  • afterend: Inserts content after the element closing tag

A visual representation of this is as follows:

<!-- beforebegin -->
<div class="parent-class">
    <!-- afterbegin -->
    <div class="existing-content">
    <!-- beforeend -->
</div>
<!-- afterend -->

The direct replacement for += would be beforeend.

Using insertHTML retains the event listeners currently attached to the content within the parent.

If you like what we do, consider supporting us on Ko-fi