Jules
Jules

Reputation: 107

How to find out when, where, how an eventListener is added and removed in Chrome dev tools

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

Answers (2)

CertainPerformance
CertainPerformance

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

Slawomir Chodnicki
Slawomir Chodnicki

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

Related Questions