Philipp Gfeller
Philipp Gfeller

Reputation: 1259

Remove event listener vanilla JS

I have a special scenario described as short as possible in this pen: http://codepen.io/tuelsch/pen/rVRRNm?editors=101

This article (Adding and Removing Event Listeners with parameters) pointed me in the right direction but has a different setup.

I like to have a custom JS object (Film) which can add and remove event handler on its link property (a DOM element).

I'm stuck with the removeEvent function on line 18. What is the correct second argument for the removeEventListener function in this case?

Instead of adding and removing the event listener, it just keeps adding event listeners, as can be observed in the console, where the result of line 8 is logged.

The solution should be plain vanilla JavaScript, ES5 compatible and intended to run in the browser (IE9+).

Upvotes: 0

Views: 7102

Answers (2)

fuyushimoya
fuyushimoya

Reputation: 9813

  1. You can first keep the record of that binded event in your object like:
// Add the event handler
Film.prototype.bindEvent = function () {
  // This ensure that the binded event can be removed by removeEvent
  // even if you call bindEvent many times.
  if (!this._bindedEvent) {
    this._bindedEvent = this.eventHandler.bind(this);
    this.link.addEventListener('click', this._bindedEvent);
  }
}

Then remove that:

// Remove the event handler
Film.prototype.removeEvent = function () {
  if (this._bindedEvent) {
    this.link.removeEventListener('click', this._bindedEvent); 
    this._bindedEvent = null;
  }
}

2 . Another way is to override eventhandler in constructor:

// The test class definition
var Film = function () {
  this.link = document.getElementById('film');
  // This first find if self has attr eventHandler, and keep lookup to its prototype.
  // Then createa binded version of eventhandler and set to this's attr.
  // So when you try to access `this.eventHandler`, it'll be the binded version instead of Prototype's
  this.eventHandler = this.eventHandler.bind(this);
}

Then you can just use

// Add the event handler
Film.prototype.bindEvent = function () {
    this.link.addEventListener('click', this.eventHandler);
}

// Remove the event handler
Film.prototype.removeEvent = function () {
    this.link.removeEventListener('click', this.eventHandler); 
}

To add and remove it.

Upvotes: 3

Ori Drori
Ori Drori

Reputation: 191976

When you use .bind(this) as you do here: this.link.addEventListener('click', this.eventHandler.bind(this)); you actually get a new function. When you try to remove it, you use the original handler, and the remove can't find the binded handler.

From MDN:

The bind() method creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called.

To fix that use the bind when you define the handler (codepen - the handler is removed after 3 seconds):

// The event handler to add and remove
Film.prototype.eventHandler = function () {
  console.log('handled');
}.bind(Film);

// Add the event handler
Film.prototype.bindEvent = function () {
  this.link.addEventListener('click', this.eventHandler);
}

// Remove the event handler
Film.prototype.removeEvent = function () {
  this.link.removeEventListener('click', this.eventHandler);
}

Upvotes: 1

Related Questions