StueyTheScout StueyTheScout - 10 months ago 46
HTML Question

I am having issues with es6 classes and event listeners?

Basically I am having issues with ES6 Classes and event listeners. Or it could very well just be my understanding of the whole thing.

I am dynamically creating 5 instances of the same class called 'Thing'. Each 'Thing' writes a piece of HTML to the DOM containing a button and adds an event listener to handle clicks. Elements are being selected using document.querySelector and based off a data attribute called 'indexNumber' to uniquely identify each button.

As each thing is its own instance I imagined that each button would work but only the last button does. Why is one instance of a class overwriting another?

Can anyone explain what is happening here?

I have created this pen to demonstrate the problem I am having:


<span class="output"></span>
<div class="thingHolder"></div>

JS (Babel)

class Thing {
constructor(index) {
this.Index = index;
this.html = '<div class="thing" data-index-number="'+ index +'">Thing ' + index + '<button type="button">Click Me!</button></div>';
const thingHolder = document.querySelector(".thingHolder");
thingHolder.innerHTML += this.html;


const button = document.querySelector('.thingHolder .thing[data-index-number="' + this.Index + '"] button');

button.addEventListener("click", () => {
}, false);

const output = document.querySelector(".output");
output.innerHTML = 'You clicked thing #' + this.Index;
console.log('You clicked thing #' + this.Index)

for(var i = 0; i < 5; i++) {
var thing = new Thing(i);

Answer Source

When you use thingHolder.innerHTML += html the old objects in the container are removed and recreated, but without their event listeners. So you are recreating them all every time you insert a new node that way.

The fact that the first button is the only one that works is because you are attaching an event only to the first element you encounter inside the parent (with querySelector), just after you removed all other events.

So the solution would be to create your elements with JS (or whatever is used in Babel) instead of using innerHTML.