question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Rule proposal: Disallow calling add/removeEventListener with the result of a bound function call

See original GitHub issue

Calling this.addEventListener('event', myFunc.bind(this)) and this.removeEventListener('event', myFunc.bind(this)) has always been an indication of an error to me. The corresponding removeEventListener isn’t actually doing anything because the .bind call creates a new function.

Not sure what I’d call this rule. disallow-anonymous-event-handler ?

This was requested in eslint but for some reason got rejcted.

Fail

class MyClass extends HTMLElement {
  connectedCallback() {
    this.addEventListener('click', this.handleClick.bind(this));
  }

  disconnectedCallback() {
    this.removeEventListener('click', this.handleClick.bind(this));
  }

  handleClick() { /* ... */ }
}

Pass

class MyClass extends HTMLElement {
  connectedCallback() {
    this.addEventListener('click', this.handleClick);
  }

  disconnectedCallback() {
    this.removeEventListener('click', this.handleClick);
  }

  handleClick = () => { /* ... */ }
}

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Reactions:1
  • Comments:11 (6 by maintainers)

github_iconTop GitHub Comments

2reactions
bschlenkcommented, Apr 14, 2020

It’s valid code in that it doesn’t throw any errors, but it doesn’t remove the event listener. That would be the reason to have this rule.

What about this case:

this.addEventListener('click', this.handleClick.bind(this));
this.removeEventListener('click', this.handleClick)

I’ve seen someone write this code too. The removeEventListener call isn’t using bind, but it is still broken.

Maybe it can be configurable which methods it disallows? I’d set it up to fail on both, since there are plenty of alternatives to bind that work. But someone else can set it up only to fail for removeEventListener. The point is to prevent code that can easily cause errors.

1reaction
fiskercommented, Apr 23, 2021

We’ll forbid any listener that it’s not a reference, including

foo.removeEventListener('click', function () {})
foo.removeEventListener('click', () => {})
foo.removeEventListener('click', bar.bind(null))
Read more comments on GitHub >

github_iconTop Results From Across the Web

How can I add a removable event listener to a list of elements ...
You can generate a list of functions and use them to remove the listener: let removers = elementList.map((el, idx) => { let handler ......
Read more >
EventTarget.removeEventListener() - Web APIs | MDN
The removeEventListener() method of the EventTarget interface removes an event listener previously registered with EventTarget.
Read more >
Google TypeScript Style Guide
This guide is based on the internal Google TypeScript style guide, but it has been slightly adjusted to remove Google-internal sections.
Read more >
removeEventListener() should be called with a correct listener
This rule applies when removeEventListener() is called with a wrong listener. The removeEventListener() method can only remove the exact ...
Read more >
five ways to get out of an event handling mess
should always remove your event listeners when you're done with ... to keep a reference to the event handling function around so you...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found