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


Here is my problem: is it possible somehow to check for existence of dynamically attached event listener? Or how can I check the status of the "onclick" (?) property in DOM? I have searched 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 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]", event fires well, but the "Test link 2" always reports false. Can somebody help?

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'));

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 (untested):

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

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

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

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

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

   return events[name].length);
}

Just remove the event before adding it :

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

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)}();

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


There is no way to check whether dynamically attached event listeners exist or not.

The only way you can see if an event listener is attached is by attaching event listeners like this:

elem.onclick = function () { console.log (1) }

You can then test if an event listener was attached to onclick by returning !!elem.onclick (or something similar).


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 special attribute for an element when listener is attached and then checking if it exist.


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);
 }
}

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:

window.onload = function () {
  var
    /* Cache the test element. */
    element = document.getElementById("test"),

    /* Create an event listener. */
    listener = function (e) {
      console.log(e.type + "triggered!");
    };

  /* Insert the listener to the element. */
  insertListener(element, "mouseover", listener);

  /* Log whether the listener exists. */
  console.log(listenerExists(element, "mouseover", listener));

  /* Remove the listener from the element. */
  removeListener(element, "mouseover", listener);

  /* Log whether the listener exists. */
  console.log(listenerExists(element, "mouseover", listener));
};
<!-- Include the Custom Event Storage file -->
<script src = "https://cdn.rawgit.com/angelpolitis/custom-event-storage/master/main.js"></script>

<!-- A Test HTML element -->
<div id = "test" style = "background:#000; height:50px; width: 50px"></div>


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. ????


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');
}

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.


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

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.