A wild handleEvent appeared ๐Ÿ˜ฎ !!!

A wild handleEvent appeared ๐Ÿ˜ฎ !!!

ยท

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'));

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);

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)
    })
  }
}

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!!!'),
});

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')
  });

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');

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

Did you find this article valuable?

Support Lakshya Thakur by becoming a sponsor. Any amount is appreciated!

ย