Reputation: 107
I have an tag that in some point in my JS application gets a click eventListener. And unexpectedly gets a second click event listener further in time. I expect the first one to be removed first, before it is added again.
How can i use the chrome dev tools to determine when an event listener is added, removed, and which code caused it, including a call stack?
I tried console logging stuff but i still cannot see the cause.
The adding and removing of listeners is done in such functions
class SomeClass {
/**
* Enables listeners so that clicking on the navigatableElement can work.
*/
enableListeners() {
this.disableListeners();
this._navigatableElement.addEventListener('click', this._clickEventHandler.bind(this));
}
/**
* Disables listeners so that clicking on the navigatableElement will never trigger the confirmation modal anymore via this controller
*/
disableListeners() {
this._navigatableElement.removeEventListener('click', this._clickEventHandler.bind(this));
}
}
Upvotes: 1
Views: 808
Reputation: 371168
One possible method that can be used for debugging (but not in production code) is to write to Element.prototype.addEventListener
, allowing you to log and console.trace
whenever it's called:
const { addEventListener, removeEventListener } = EventTarget.prototype;
Element.prototype.addEventListener = function(...args) {
console.log('Adding event listener!', this, args);
console.trace();
// debugger
return addEventListener.apply(this, args);
};
Element.prototype.removeEventListener = function(...args) {
console.log('Removing event listener!', this, args);
console.trace();
// debugger
return removeEventListener.apply(this, args);
};
console.log('real script start');
const fn = () => console.log('fn');
foo.addEventListener('click', fn);
console.log('listener added.');
foo.removeEventListener('click', fn);
<div id="foo">
</div>
Your particular code is not working because every time you .bind
, you're creating a new function. You can use the common React pattern of binding in the constructor, that way every reference to this._clickEventHandler
will be to the same function. (removeEventListener
needs to be called with the exact same function reference addEventListener
was called with to work.)
class SomeClass {
constructor() {
this._clickEventHandler = this._clickEventHandler.bind(this);
}
/**
* Enables listeners so that clicking on the navigatableElement can work.
*/
enableListeners() {
this.disableListeners();
this._navigatableElement.addEventListener('click', this._clickEventHandler);
}
/**
* Disables listeners so that clicking on the navigatableElement will never trigger the confirmation modal anymore via this controller
*/
disableListeners() {
this._navigatableElement.removeEventListener('click', this._clickEventHandler);
}
}
Upvotes: 1
Reputation: 1545
Your removal code does not work, because every call to .bind()
generates a new function object. You're asking to remove a listener the browser does not see as registered and it ignores the call.
Upvotes: 2