0

I am trying to conditionally add and remove event listeners on a button when the window is resized. To be able to remove the event listener, it has to be a named function.

The problem is it messes with this context, and therefore this.element in my handle() function is not accessible.

I can bind this and pass it along:

this.button.addEventListener('click', this.handle.bind(this)); 

But then it does not get removed, as it appears to not be the same event listener. Can i pass this differently, or is there some other way to remove event listeners? I have tried to clone the element and replace it, but then the event listener does not get reattached.

As per here: How to remove all listeners in an element?

Here is some simplified code:

export default class Classname {

  constructor(element, button) {
    this.button = button;
    this.element = document.querySelector(element);
    this.resize();
  }

  handle() {
    // do stuff
    console.log(this.element);
  }

  clickEvents() {
    if (condition) {
      this.button.addEventListener('click', this.handle);
    } else {
      this.button.removeEventListener('click', this.handle);
    }
  }

  resize() {
    window.addEventListener('resize', () => {
      this.clickEvents();
    })
  }
}
Rastur
  • 137
  • 1
  • 3
  • 12
  • Just a quick note: it might not be the best idea to bind a click event listener repeatedly during a resize event, unless you are very sure the `condition` evaluates to true once. Otherwise you might risk binding multiple identical event listeners. – Terry Mar 02 '19 at 21:23
  • @ Terry: No worries, `resize` is wired via `debounce`, and the condition is a media query breakpoint. – Rastur Mar 02 '19 at 21:25

2 Answers2

2

You can assign the bound handler to a property of the instance, and then pass that bound handler to both addEventListener and, later, removeEventListener:

clickEvents() {
  if (condition) {
    this.boundHandler = this.handle.bind(this);
    this.button.addEventListener('click', this.boundHandle);
  } else {
    this.button.removeEventListener('click', this.boundHandle);
  }
}

Another possibility would be to bind in the constructor instead:

constructor(element, button) {
  this.boundHandler = this.handle.bind(this);
  this.button = button;
  this.element = document.querySelector(element);
  this.resize();
}
CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
1

You can convert the handle method to an arrow function and then the this will be retained.

  handle = () => {
    // do stuff
    console.log(this.element);
  }
Gabriele Petrioli
  • 191,379
  • 34
  • 261
  • 317