TIL: Listen for JavaScript events only once!

A common thing I find myself doing in Javascript is adding some event driven behavior that I only want to happen once. Let’s say I have a big button that starts the process of lowering a certain spy into a pool of certain doom — I don’t want a second button press to awkwardly start him back at the top again!

This usually means that I’m doing a dance of calling removeEventListener from within my event handler.

let doombutton = document.querySelector("button")

function youOnlyClickOnce(){
alert("Just this once, Mr. Bond!")
doombutton.removeEventListener("click", youOnlyClickOnce)

doombutton.addEventListener("click", youOnlyClickOnce)

This pattern is no big deal in simple contexts, but I often get tripped up by the requirement that the call to removeEventListener be exactly the same as the original addEventListener call. If your event handler is in a different scope then where you set up the listener, things get squirrelly.

When you're working with classes, you typically need make sure you’ve bound your handler to the correct scope to get the remove call to work:

class ButtonListener {
constructor() {
this.doombutton = document.querySelector("button")
this.boundYouOnlyClickOnce = this.youOnlyClickOnce.bind(this);
this.doombutton.addEventListener("click", this.boundYouOnlyClickOnce)

youOnlyClickOnce() {
alert("Just this once, Mr. Bond!")
this.doombutton.removeEventListener("click", this.boundYouOnlyClickOnce)

new ButtonListener();

It's easy to see how working with a lot of event handlers and similar behaviors can quickly pile the code up with more spaghetti than a dinner plate at my mother-in-law’s. Just kidding, nobody has more spaghetti than that.

Well, today I had an amazing happy accident while debugging something completely unrelated! addEventListener takes an option called once which removes the listener automagically after its first invoked.

mybutton.addEventListener(“click”, youOnlyClickOnce, { once: true })

That glorious nugget removes all need to ever call removeEventListener or worry about bound scopes or anything like that. Just set your event listener and move on with your life.

But not yours, Mr. Bond. Muahahahahaahaha.