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?
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: EventTarget: addEventListener() method - Web APIs | MDN
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 Likes
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: Component - 4.6 - Ember API Documentation, 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!
@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.