[javascript] How to check whether dynamically attached event listener exists or not?

Here is my problem: is it somehow possible to check for the existence of a dynamically attached event listener? Or how can I check the status of the "onclick" (?) property in the DOM? I have searched the internet just like Stack Overflow for a solution, but no luck. Here is my html:

<a id="link1" onclick="linkclick(event)"> link 1 </a>
<a id="link2"> link 2 </a> <!-- without inline onclick handler -->

Then in Javascript I attach a dynamically created event listener to the 2nd link:

document.getElementById('link2').addEventListener('click', linkclick, false);

The code runs well, but all my attempts to detect that attached listener fail:

// test for #link2 - dynamically created eventlistener
alert(elem.onclick); // null
alert(elem.hasAttribute('onclick')); // false
alert(elem.click); // function click(){[native code]} // btw, what's this?

jsFiddle is here. If you click "Add onclick for 2" and then "[link 2]", the event fires well, but the "Test link 2" always reports false. Can somebody help?

This question is related to javascript testing addeventlistener dom-events

The answer is


You could in theory piggyback addEventListener and removeEventListener to add remove a flag to the 'this' object. Ugly and I haven't tested ...


If I understand well you can only check if a listener has been checked but not which listener is presenter specifically.

So some ad hoc code would fill the gap to handle your coding flow. A practical method would be to create a state using variables. For example, attach a listener's checker as following:

var listenerPresent=false

then if you set a listener just change the value:

listenerPresent=true

then inside your eventListener 's callback you can assign specific functionalities inside and in this same way, distribute the access to functionalities depending of some state as variable for example:

accessFirstFunctionality=false
accessSecondFunctionality=true
accessThirdFunctionality=true

There doesn't appear to be a cross browser function that searches for events registered under a given element.

However, it is possible to view the call back functions for elements in some browsers using their development tools. This can be useful when attempting to determine how a web page functions or for debugging code.

Firefox

First, view the element in the Inspector tab within the developer tools. This can be done:

  • On the page by right clicking on the item on the web page that you want to inspect and selecting "Inspect Element" from the menu.
  • Within the console by using a function to select the element, such as document.querySelector, and then clicking the icon beside the element to view it in the Inspector tab.

If any events were registered to the element, you will see a button containing the word Event beside the element. Clicking it will allow you to see the events that have been registered with the element. Clicking the arrow beside an event allows you to view the callback function for it.

Chrome

First, view the element in the Elements tab within the developer tools. This can be done:

  • On the page by right clicking on the item on the web page that you want to inspect and selecting "Inspect" from the menu
  • Within the console by using a function to select the element, such as document.querySelector, right clicking the the element, and selecting "Reveal in Elements panel" to view it in the Inspector tab.

Near the section of the window that shows the tree containing the web page elements, there should be another section with a tab entitled "Event Listeners". Select it to see events that were registered to the element. To see the code for a given event, click the link to the right of it.

In Chrome, events for an element can also be found using the getEventListeners function. However, based on my tests, the getEventListeners function doesn't list events when multiple elements are passed to it. If you want to find all of the elements on the page that have listeners and view the callback functions for those listeners, you can use the following code in the console to do this:

var elems = document.querySelectorAll('*');

for (var i=0; i <= elems.length; i++) {
    var listeners = getEventListeners(elems[i]);

    if (Object.keys(listeners).length < 1) {
        continue;
    }

    console.log(elems[i]);

    for (var j in listeners) {
        console.log('Event: '+j);

        for (var k=0; k < listeners[j].length; k++) {
            console.log(listeners[j][k].listener);
        }
    }
}

Please edit this answer if you know of ways to do this in the given browsers or in other browsers.


I just found this out by trying to see if my event was attached....

if you do :

item.onclick

it will return "null"

but if you do:

item.hasOwnProperty('onclick')

then it is "TRUE"

so I think that when you use "addEventListener" to add event handlers, the only way to access it is through "hasOwnProperty". I wish I knew why or how but alas, after researching, I haven't found an explanation.


I did something like that:

const element = document.getElementById('div');

if (element.getAttribute('listener') !== 'true') {
     element.addEventListener('click', function (e) {
         const elementClicked = e.target;
         elementClicked.setAttribute('listener', 'true');
         console.log('event has been attached');
    });
}

Creating a special attribute for an element when the listener is attached and then checking if it exists.


You could always check manually if your EventListener exist using Chrome inspector for example. In Element tab you have the traditional "Styles" subtab and close to it another one : "Event Listeners". Which will give you the list of all EventListeners with their linked elements.


Here's a script I used to check for the existence of a dynamically attached event listener. I used jQuery to attach an event handler to an element, then trigger that event (in this case the 'click' event). This way I can retrieve and capture event properties that will only exist if the event handler is attached.

var eventHandlerType;

$('#contentDiv').on('click', clickEventHandler).triggerHandler('click');

function clickEventHandler(e) {
    eventHandlerType = e.type;
}

if (eventHandlerType === 'click') {
    console.log('EventHandler "click" has been applied');
}

It seems odd that this method doesn't exist. Is it time to add it finally?

If you wanted to you could something like the following:

var _addEventListener = EventTarget.prototype.addEventListener;
var _removeEventListener = EventTarget.prototype.removeEventListener;
EventTarget.prototype.events = {};
EventTarget.prototype.addEventListener = function(name, listener, etc) {
  var events = EventTarget.prototype.events;
  if (events[name] == null) {
    events[name] = [];
  }

  if (events[name].indexOf(listener) == -1) {
    events[name].push(listener);
  }

  _addEventListener(name, listener);
};
EventTarget.prototype.removeEventListener = function(name, listener) {
  var events = EventTarget.prototype.events;

  if (events[name] != null && events[name].indexOf(listener) != -1) {
    events[name].splice(events[name].indexOf(listener), 1);
  }

  _removeEventListener(name, listener);
};
EventTarget.prototype.hasEventListener = function(name) {
  var events = EventTarget.prototype.events;
  if (events[name] == null) {
    return false;
  }

  return events[name].length;
};

I just wrote a script that lets you achieve this. It gives you two global functions: hasEvent(Node elm, String event) and getEvents(Node elm) which you can utilize. Be aware that it modifies the EventTarget prototype method add/RemoveEventListener, and does not work for events added through HTML markup or javascript syntax of elm.on_event = ...

More info at GitHub

Live Demo

Script:

var hasEvent,getEvents;!function(){function b(a,b,c){c?a.dataset.events+=","+b:a.dataset.events=a.dataset.events.replace(new RegExp(b),"")}function c(a,c){var d=EventTarget.prototype[a+"EventListener"];return function(a,e,f,g,h){this.dataset.events||(this.dataset.events="");var i=hasEvent(this,a);return c&&i||!c&&!i?(h&&h(),!1):(d.call(this,a,e,f),b(this,a,c),g&&g(),!0)}}hasEvent=function(a,b){var c=a.dataset.events;return c?new RegExp(b).test(c):!1},getEvents=function(a){return a.dataset.events.replace(/(^,+)|(,+$)/g,"").split(",").filter(function(a){return""!==a})},EventTarget.prototype.addEventListener=c("add",!0),EventTarget.prototype.removeEventListener=c("remove",!1)}();

Possible duplicate: Check if an element has event listener on it. No jQuery Please find my answer there.

Basically here is the trick for Chromium (Chrome) browser:

getEventListeners(document.querySelector('your-element-selector'));

What I would do is create a Boolean outside your function that starts out as FALSE and gets set to TRUE when you attach the event. This would serve as some sort of flag for you before you attach the event again. Here's an example of the idea.

// initial load
var attached = false;

// this will only execute code once
doSomething = function()
{
 if (!attached)
 {
  attached = true;
  //code
 }
} 

//attach your function with change event
window.onload = function()
{
 var txtbox = document.getElementById('textboxID');

 if (window.addEventListener)
 {
  txtbox.addEventListener('change', doSomething, false);
 }
 else if(window.attachEvent)
 {
  txtbox.attachEvent('onchange', doSomething);
 }
}

I usually attach a class to the element then check if the class exist like this:

let element = document.getElementsById("someElement");

if(!element.classList.contains('attached-listener'))
   element.addEventListener("click", this.itemClicked);

element.classList.add('attached-listener');

Just remove the event before adding it :

document.getElementById('link2').removeEventListener('click', linkclick, false);
document.getElementById('link2').addEventListener('click', linkclick, false);

tl;dr: No, you cannot do this in any natively supported way.


The only way I know to achieve this would be to create a custom storage object where you keep a record of the listeners added. Something along the following lines:

/* Create a storage object. */
var CustomEventStorage = [];

Step 1: First, you will need a function that can traverse the storage object and return the record of an element given the element (or false).

/* The function that finds a record in the storage by a given element. */
function findRecordByElement (element) {
    /* Iterate over every entry in the storage object. */
    for (var index = 0, length = CustomEventStorage.length; index < length; index++) {
        /* Cache the record. */
        var record = CustomEventStorage[index];

        /* Check whether the given element exists. */
        if (element == record.element) {
            /* Return the record. */
            return record;
        }
    }

    /* Return false by default. */
    return false;
}

Step 2: Then, you will need a function that can add an event listener but also insert the listener to the storage object.

/* The function that adds an event listener, while storing it in the storage object. */
function insertListener (element, event, listener, options) {
    /* Use the element given to retrieve the record. */
    var record = findRecordByElement(element);

    /* Check whether any record was found. */
    if (record) {
        /* Normalise the event of the listeners object, in case it doesn't exist. */
        record.listeners[event] = record.listeners[event] || [];
    }
    else {
        /* Create an object to insert into the storage object. */
        record = {
            element: element,
            listeners: {}
        };

        /* Create an array for event in the record. */
        record.listeners[event] = [];

        /* Insert the record in the storage. */
        CustomEventStorage.push(record);
    }

    /* Insert the listener to the event array. */
    record.listeners[event].push(listener);

    /* Add the event listener to the element. */
    element.addEventListener(event, listener, options);
}

Step 3: As regards the actual requirement of your question, you will need the following function to check whether an element has been added an event listener for a specified event.

/* The function that checks whether an event listener is set for a given event. */
function listenerExists (element, event, listener) {
    /* Use the element given to retrieve the record. */
    var record = findRecordByElement(element);

    /* Check whether a record was found & if an event array exists for the given event. */
    if (record && event in record.listeners) {
        /* Return whether the given listener exists. */
        return !!~record.listeners[event].indexOf(listener);
    }

    /* Return false by default. */
    return false;
}

Step 4: Finally, you will need a function that can delete a listener from the storage object.

/* The function that removes a listener from a given element & its storage record. */
function removeListener (element, event, listener, options) {
    /* Use the element given to retrieve the record. */
    var record = findRecordByElement(element);

    /* Check whether any record was found and, if found, whether the event exists. */
    if (record && event in record.listeners) {
        /* Cache the index of the listener inside the event array. */
        var index = record.listeners[event].indexOf(listener);

        /* Check whether listener is not -1. */
        if (~index) {
            /* Delete the listener from the event array. */
            record.listeners[event].splice(index, 1);
        }

        /* Check whether the event array is empty or not. */
        if (!record.listeners[event].length) {
            /* Delete the event array. */
            delete record.listeners[event];
        }
    }

    /* Add the event listener to the element. */
    element.removeEventListener(event, listener, options);
}

Snippet:

_x000D_
_x000D_
window.onload = function () {_x000D_
  var_x000D_
    /* Cache the test element. */_x000D_
    element = document.getElementById("test"),_x000D_
_x000D_
    /* Create an event listener. */_x000D_
    listener = function (e) {_x000D_
      console.log(e.type + "triggered!");_x000D_
    };_x000D_
_x000D_
  /* Insert the listener to the element. */_x000D_
  insertListener(element, "mouseover", listener);_x000D_
_x000D_
  /* Log whether the listener exists. */_x000D_
  console.log(listenerExists(element, "mouseover", listener));_x000D_
_x000D_
  /* Remove the listener from the element. */_x000D_
  removeListener(element, "mouseover", listener);_x000D_
_x000D_
  /* Log whether the listener exists. */_x000D_
  console.log(listenerExists(element, "mouseover", listener));_x000D_
};
_x000D_
<!-- Include the Custom Event Storage file -->_x000D_
<script src = "https://cdn.rawgit.com/angelpolitis/custom-event-storage/master/main.js"></script>_x000D_
_x000D_
<!-- A Test HTML element -->_x000D_
<div id = "test" style = "background:#000; height:50px; width: 50px"></div>
_x000D_
_x000D_
_x000D_


Although more than 5 years have passed since the OP posted the question, I believe people who stumble upon it in the future will benefit from this answer, so feel free to make suggestions or improvements to it.


Examples related to javascript

need to add a class to an element How to make a variable accessible outside a function? Hide Signs that Meteor.js was Used How to create a showdown.js markdown extension Please help me convert this script to a simple image slider Highlight Anchor Links when user manually scrolls? Summing radio input values How to execute an action before close metro app WinJS javascript, for loop defines a dynamic variable name Getting all files in directory with ajax

Examples related to testing

Test process.env with Jest How to configure "Shorten command line" method for whole project in IntelliJ Jest spyOn function called Simulate a button click in Jest Mockito - NullpointerException when stubbing Method toBe(true) vs toBeTruthy() vs toBeTrue() How-to turn off all SSL checks for postman for a specific site What is the difference between smoke testing and sanity testing? ReferenceError: describe is not defined NodeJs How to properly assert that an exception gets raised in pytest?

Examples related to addeventlistener

How to bind event listener for rendered elements in Angular 2? Dynamically add event listener Cannot read property 'addEventListener' of null Why doesn't document.addEventListener('load', function) work in a greasemonkey script? How to check whether dynamically attached event listener exists or not? Javascript: Uncaught TypeError: Cannot call method 'addEventListener' of null addEventListener not working in IE8 How to remove all listeners in an element? Binding multiple events to a listener (without JQuery)? addEventListener in Internet Explorer

Examples related to dom-events

Detecting real time window size changes in Angular 4 Does Enter key trigger a click event? What are passive event listeners? Stop mouse event propagation React onClick function fires on render How do you Hover in ReactJS? - onMouseLeave not registered during fast hover over iFrame onload JavaScript event addEventListener, "change" and option selection Automatically pass $event with ng-click? JavaScript click event listener on class