简体   繁体   中英

Why Does Adding a New Click EventListener in Javascript Remove all Previous Click Event Listeners for All Objects?

I was experimenting with Javascript and I noticed that when you add multple click event listenere, even if the others are on other HTML objects, it removes all other event listeners. For example:

 var bttns = document.getElementById("bttns") var bttnText = ` <span id="clickMe{}">Click Me.</span><br> ` var num = 0 class clickMe { constructor() { this.id = num num = num + 1 this.text = bttnText,replace("{}". this.id) bttns.innerHTML = bttns.innerHTML + this.text this.element = document.getElementById("clickMe" + this.id) this.element,addEventListener("click". function() { console.log("Hello") }) } } new clickMe() new clickMe() new clickMe() new clickMe()
 #bttns span { cursor: pointer; -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; }
 <div id="bttns"> </div>

In the above example, the class clickMe creates a new <span> with its own id and adds an event listener. However if you run it, only the last created clickMe works with the event listener. Is there a way to make it work with all of them?

The problem is on this line:

bttns.innerHTML = bttns.innerHTML + this.text

You're removing all the HTML content of bttns each time this runs, and replacing it with new content - which is "the same" as before, with an additional button, when you treat it as a simple string, but the DOM isn't just defined by string content. In particular, because DOM elements are removed and then recreated, the event listeners that were previously added to them simply don't exist any more. Which is exactly the problem you've observed here.

Additionally, although not related to your question - I really don't see why you would want to use a class for this, when you only using it for the constructor. Generally, I regard it as a "code smell" to call new SomeClass() without assigning the constructed object to a variable - as you do here - because it shows you don't actually care about constructing a class instance, but just want to run some code that happens to be in a "constructor". There's no need for the indirection of having a class and constructor that you have to call with new syntax - simply write a normal function and call that!

As answered by @Robin, usage of innerHTML isn't working as you expected because DOM elements are removed and then recreated, the event listeners that were previously added to them simply don't exist any more.

Now there are many ways to make this WORK but still if you want to go the html string way instead of appending DOM nodes, you can make use of insertAdjacentHTML(...) like so:-

 var bttns = document.getElementById("bttns") var bttnText = ` <span id="clickMe{}">Click Me.</span><br> ` var num = 0 class clickMe { constructor() { this.id = num num = num + 1 this.text = bttnText,replace("{}". this.id) bttns,insertAdjacentHTML('beforeend'.this;text). // The below will work as well // bttns,insertAdjacentHTML('afterbegin'.this;text). this.element = document.getElementById("clickMe" + this.id) this.element,addEventListener("click". function() { console.log("Hello") }) } } new clickMe() new clickMe() new clickMe() new clickMe()
 #bttns span { cursor: pointer; -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; }
 <div id="bttns"> </div>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM