[Solved] How to remove event handler properly in a component?


#1

I did something like below in component(s):


didInsertElement() {
    window.addEventListener('scroll', this._scrollingHandler.bind(this), false)
},

willDestroyElement() {
    window.removeEventListener('scroll', this._scrollingHandler, false)  // this line did run, confirmed
}

I thought it would removes the event handler bound to window, but it did not! even the removeEventListener is actually run (confirmed by setting break point at here), this._scrollingHandler still responding when scrolling happens.

What I did wrong? What is the correct way to remove / cleanup for a component?


#2

The problem is you’re using Function.prototype.bind, as it creates a new Function. So, when you remove it with this._scrollHandler it’s pointing to an entirely different function that it does not have a event handler for so it results in a noop.

A good read on this: https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#The_value_of_this_within_the_handler

Specifically, the part where it states:

A problem in the example above is that you cannot remove the listener with bind. Another solution is using a special function called handleEvent to catch any events…

You can go the handleEvent approach using something like this mixin I wrote, https://github.com/jasonmit/virtual-each/blob/master/addon/mixins/event-listener.js, or:

didInsertElement() {
    this._onScroll = this._scrollingHandler.bind(this);
    window.addEventListener('scroll', this._onScroll, false);
},

willDestroyElement() {
    window.removeEventListener('scroll', this._onScroll, false);
}

#3

Ah, thanks very much, I didn’t realize the bind problem, but it indeed make senses.

Also, I was trying to use the handleEvent method: http://emberjs.com/api/classes/Ember.Component.html#method_handleEvent, but it been labeled as private, it makes me struggled a lot.

Your way to solve this is very simple and clear, wish it could be found in official document, very useful!


#4

@jasonmit Thank you for posting that. I was also unaware of that bind gotcha. Your mixin is an elegant solution to what could be a vexing bug.