Search code examples
javascriptecmascript-6addeventlistenercustom-elementremoveeventlistener

Remove event listener that has been added using bind(this)


How do I remove the click listener I bound to window in the constructor below? I need it to listen on window, and I need access to the button instance inside it.

class MyEl extends HTMLButtonElement {
  constructor() {
    super();
    this.clickCount = 0;
    window.addEventListener('click', this.clickHandler.bind(this));
  }
  
  clickHandler(e) {
    if (e.target === this) {
      this.textContent = `clicked ${++this.clickCount} times`;
      window.removeEventListener('click', this.clickHandler);
    }
  }
  
  disconnectedCallback() {
      window.removeEventListener('click', this.clickHandler);
  }
}

customElements.define('my-el', MyEl, { extends: 'button' });
<button is="my-el" type="button">Click me</button>


Solution

  • It's not possible with your current implementation - every call of .bind creates a new separate function, and you can only call removeEventListener to remove a listener if the passed function is the same (===) as the one passed to addEventListener (just like .includes for arrays, or .has for Sets):

    const fn = () => 'foo';
    console.log(fn.bind(window) === fn.bind(window));

    As a workaround, you could assign the bound function to a property of the instance:

    class MyEl extends HTMLButtonElement {
      constructor() {
        super();
        this.clickCount = 0;
        this.boundListener = this.clickHandler.bind(this);
        window.addEventListener('click', this.boundListener);
      }
      
      clickHandler(e) {
        this.textContent = `clicked ${++this.clickCount} times`;
        window.removeEventListener('click', this.boundListener);
      }
    }
    
    customElements.define('my-el', MyEl, { extends: 'button' });
    <button is="my-el" type="button">Click me</button>