DEV Community

loading...
Cover image for A wild handleEvent appeared ๐Ÿ˜ฎ !!!

A wild handleEvent appeared ๐Ÿ˜ฎ !!!

Lakshya Thakur
I like to have creative insights towards my subjects and apply my engineering skills for problem solving.
Originally published at blog.lakbychance.com ใƒป3 min read

Let's say, we have a DOM element by the name of element and we want to add event listeners to it. How would you do so ?

Here are two ways which can come into mind :-

const handleClick = () =>{console.log('You can remove me later safely')}
element.addEventListener('click',handleClick);
element.addEventListener('click',()=>console.log('Try and remove me noob'));
Enter fullscreen mode Exit fullscreen mode

Now when it comes to removing these event listeners, it's not possible to remove the second one since it's anonymous and for first one we can just do element.removeEventListener('click',handleClick);

What if I told you there is a way and a syntax you might not be familiar with when it comes to event listeners ?

you're lying

Well here it is :-

const someObj = {
handleEvent: (e)=>console.log(`I am ${e.type} event`);
}

element.addEventListener('click',someObj);
Enter fullscreen mode Exit fullscreen mode

And :-

this is fine

Jokes aside, it's always been there. It's just less spoken about. And I came across this when I solved this StackOverflow question and my mind was blowwwwnn !!!

mind blown

Also, You can just remove the event listener like so element.removeEventListener('click',someObj);

After finding this, I thought to myself that what if I make a bare minimum Handler class which can abstract the registration and unregistration bit and work on the same principle ?

And this is how it looks :-

class Handler {
  #element
  #eventMap = {}

  constructor(element, eventMap) {
    this.#element = element
    this.register(eventMap)
  }

  handleEvent(e) {
    this.#eventMap[e.type](e)
  }

  register(eventMap) {
    this.#eventMap = { ...this.#eventMap, ...eventMap }
    Object.keys(this.#eventMap).forEach((event) => {
      this.#element.addEventListener(event, this)
    })
  }

  unregister(event) {
    this.#element.removeEventListener(event, this)
  }

  unregisterAll() {
    Object.keys(this.#eventMap).forEach((event) => {
      this.#element.removeEventListener(event, this)
    })
  }
}
Enter fullscreen mode Exit fullscreen mode

But what made me go for a class implementation ? Well now we know that we can pass an object to add/removeEventListener, we can have a custom Handler class inside which this will point to the object instance and come into use.

Let's look at a usage sample of this code :-

const handler = new Handler(element, {
  click: ()=>console.log('Yo I am clicky'),
  focus: ()=>console.log('FOCUS!!!'),
});
Enter fullscreen mode Exit fullscreen mode

What the above does it that for element, it registers both the anonymous functions for respective events. And if you go further to register another function for click like so :-

  handler.register({
    click: () => console.log('Well I am new clicky')
  });
Enter fullscreen mode Exit fullscreen mode

This will override the existing click function that we had without any worry of handling its removal and add this new anonymous function.

Now if you want to explicitly unregister the click function, how would you do so ?

handler.unregister('click');
Enter fullscreen mode Exit fullscreen mode

that's it

So anonymous or non-anonymous, the Handler class will ensure that for each event type, only one function is registered for the same element. But what if I want to register multiple functions for same event type for the same element ?

Well in that case, you can create another instance of Handler class with same element and let it be responsible for it.

single responsibility

It's still a new concept to me and maybe I might have derived some wrong conclusions. But I will be more than happy to know more about it. Did you know this ? If so, have you used this ? Do you not prefer it ? Any bottlenecks ? Feel free to bash that comment section ๐Ÿ’ช.

You can go through this article for more insights into handleEvent.

Here is a codepen where you can play with this implementation :-

Thank you for your time :D

Discussion (1)

Collapse
ianwijma profile image
Ian Wijma

After developing using JS for the past 7 years, I though I knew almost everything of the language. But with this article I've learned that addEventListener takes a Object.

I also wanted to say that about the # usage for for class properties. But I've ESLint throw errors, where the browser console accepts using # for class properties.