Categories
Uncategorised

JS/TS – add and remove eventlisteners properly without loosing the “this” context

image by author

Before I go deeper into the topic I want to let you know if you are only searching for the solution then you can directly go to the “Solution” section in this article. Otherwise you can read from here…

JS Eventslistener

So when you want to listen for example for an “click” event on any html element, then you have to use “element.addEventListener(‘click’, myhandler);”. So every thing is cool here. Often there is a case that you register these events more than once. So it is a common and good practice to remove the listener before you register a new one. This can be done with “element.removeEventListener(‘click’, myhandler);”. So and here the problem starts…

Problem

You have two main problems when you want your “this” context stays the same (in an handler) and really want to clean the event registration. I will demonstrate the problems in the following examples. I will first setup a base test class which helps us to reduce the code which is used by all concrete test cases.

Test Setting Class

The following class is the our base class for all our coming test cases. And it is only to avoid writing redundant code. So what does this class do is first creating a div element with an id attribute in the constructor. Then it provides a method which simulates a click on this element. (this is only for testing purposes, because I do not want to create an html file…)

Use defined Event Handler

Here is our first try. We have an “addEventListener” method which first call the “removeEventListener” and then register the event handler with a defined method. After then we create an instance of the class and call “addEventListener” for multiple times. And the lasst thing is invoking the simulate click event.

So this solution does only call our defined method “onClickEventHandler” for one time, which is good. But we also loose our class instance context. So we are no more able to call another method in this class instance, because the “this” scope is now the element which was clicked…

Use anonymous Event Handler

So then you could use an anonymous function as event handler which we do in the following example. We invoke the methods in the same order and with the same count as we have done in the previous example.

Here we keep our class instance scope inside the anonymous event handler but the problem is we are not able to remove the event listener. This is because we always need to remove the event listener “instance”. But with the anonymous method we are creating every time when we add or remove the event listener a new function. So at the end our handler will be called twice – which sucks…

Use defined Method which returns Event Handler

Then you might came to the point and try to combine these two things and call a defined method which returns an event handler.

But the problem here is the same like with the anonymous functions, because at least you give the “addEventListener” function an anonymous function. We have only wrapped it into a getter.

Solution

Now it is time for the solution. Here we define first a “that” variable which contains the current “this” context. We defined an event handler as an variable and set a function (our event handler) to it. Now we have a variable which we can use to remove the listener and we can “that” for our class instance “this” context.

Conclusion

So as you can see scoping and removing listeners an be annoying, but we can solve this. But this does not change the fact that it is a little hacky, but that is javascript…