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

JavascriptTestingAddeventlistenerDom Events

Javascript Problem Overview


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?

Javascript Solutions


Solution 1 - Javascript

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.

Solution 2 - Javascript

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

Solution 3 - Javascript

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

Solution 4 - Javascript

Possible duplicate: https://stackoverflow.com/questions/28056716/check-if-an-element-has-event-listener-on-it-no-jquery/41137585#41137585 Please find my answer there.

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

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

Solution 5 - Javascript

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

Solution 6 - Javascript

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

Solution 7 - Javascript

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.

Solution 8 - Javascript

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

Solution 9 - Javascript

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.

Solution 10 - Javascript

Just remove the event before adding it :

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

Solution 11 - Javascript

// Just take this and assign the attribute outside of the anonymous function

const element = document.getElementById('div');
if (element && !element.hasAttribute('listenerOnClick')) {
    element.addEventListener('click', function () {
        const elementClicked = this;
        // fnDoAnything(this); // maybe call a function with the elementClicked...
        console.log('event has been attached');
    });
}
element.setAttribute('listenerOnClick', 'true');

Solution 12 - Javascript

2022 update:

I wrote utility methods in TypeScript to attach and detach events based on this answer but a corrected one. Hope someone finds it helpful.

export const attachEvent = (
  element: Element,
  eventName: string,
  callback: () => void
) => {
  if (element && eventName && element.getAttribute('listener') !== 'true') {
    element.setAttribute('listener', 'true');
    element.addEventListener(eventName, () => {
      callback();
    });
  }
};

export const detachEvent = (
  element: Element,
  eventName: string,
  callback: () => void
) => {
  if (eventName && element) {
    element.removeEventListener(eventName, callback);
  }
};

Import it & Use it anywhere like this

  attachEvent(domElement, 'click', this.myfunction.bind(this));
  detachEvent(domElement, 'click', this.myfunction);

Solution 13 - Javascript

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.

Solution 14 - Javascript

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

Solution 15 - Javascript

I wrote a Chrome extension that needed to determine which elements on the page responded to clicks. Here's how I did it:

(1) In manifest.json, set the "run_at" attribute to "document_start". (We need to inject a script before the page begins running.)

(2) In your content script, add a little code to inject a script into the page that will override EventTarget.prototype.addEventListener to flag all the elements that are dynamically assigned click listeners:

let flagClickHandledElements = function() {
    let oldEventListener = EventTarget.prototype.addEventListener;
    EventTarget.prototype.addEventListener = function(event_name, handler_func) {
        if (event_name === 'click') {
            if (this.setAttribute) {
                this.setAttribute('data-has_click_handler', true);
            }
        }
        if (oldEventListener)
            oldEventListener(event_name, handler_func);
    }
}

function injectScript(func) {
	let codeString = '(' + func + ')();';
	let script = document.createElement('script');
	script.textContent = codeString;
	(document.head||document.documentElement).appendChild(script);
}

injectScript(flagClickHandledElements);

(3) Add "webNavigation" to your "permissions" list in manifest.json

(4) Add some code to your background script to notify the content script when the page is done loading:

function onPageDoneLoading(details)
{
	chrome.tabs.sendMessage(details.tabId, {"action": "doneloading"});
}

chrome.webNavigation.onCompleted.addListener(onPageDoneLoading);

(5) When the page finishes loading make your content script inject another script into the page that scans all the elements on the page for old-style "onclick" handlers:

let gatherOldStyleClickHandledElements = function() {
	let all_elements = document.getElementsByTagName("*");
	for (let i = 0; i < all_elements.length; i++) {
		let el = all_elements[i];
		if (el.setAttribute && el.onclick) {
			el.setAttribute('data-has_click_handler', true);
		}
	}
}

function onReceiveMessage(request) {
	if (request.action === 'doneloading') {
		injectScript(gatherOldStyleClickHandledElements);
	} else {
		console.log('Unrecognized message');
	}

	return Promise.resolve("Dummy response to keep the console quiet");
}

(6) Finally, you can test an element in your content script to see if it has a click handler like this:

if (el.getAttribute('data-has_click_handler'))
	console.log('yep, this element has a click handler');

Solution 16 - Javascript

var listenerPaste = pasteAreaElm.hasOwnProperty('listenerPaste');
if (!listenerPaste) {
    pasteAreaElm.addEventListener("paste", onPasteEvent, false);
    pasteAreaElm.listenerPaste = true;
}

Solution 17 - Javascript

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

Solution 18 - Javascript

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

Solution 19 - Javascript

Somethings like this should help for document:

var listeners = window.getEventListeners(document);
Object.keys(listeners).forEach(event => {
    console.log(event, listeners[event]);
});

Or using selectors:

getAllEventListeners = function(el) {
 var allListeners = {}, listeners;

 while(el) {
  listeners = getEventListeners(el);

  for(event in listeners) {
   allListeners[event] = allListeners[event] || [];
   allListeners[event].push({listener: listeners[event], element: el});  
  }

  el = el.parentNode;
 }

 return allListeners;
}

Solution 20 - Javascript

It is possible to list all event listeners in JavaScript. You just have to hack the prototype's method of the HTML elements (before adding the listeners).

This solution will work only on Google Chrome or Chromium-based browsers

  1. Right-click on the element and choose “inspect” to open the Chrome developer tools.
  2. Once the dev tools are open, switch to the “Event Listeners” tab and you will see all the event listeners bound to the element.

enter image description here

Solution 21 - Javascript

Hello I propose here my method which works in a certain way to avoid ending up with several even listen on the same element of the DOM. My method uses JQUERY but the principle is as follows:

After a particular treatment of your application where you must reproduce a listener on a DOM element such as the click, then we start by deleting the event to avoid having it several times and immediately afterwards we recreate it.

This principle is to be adapted according to the needs. This is just the principle. I show you how to do it in jquery.

line 1 : $(_ELTDOM_).unbind('click');
line 2 : $(_ELTDOM_).bind('click',myFct);

I hope this can help some people by adapting this solution. I insist on the fact that this solution is not necessarily applicable in all circumstances but it already makes it possible to solve problems associated with double, triple... simultaneous processing due to several listens on the same element for example

Solution 22 - Javascript

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionStanoView Question on Stackoverflow
Solution 1 - JavascriptKarol GrabowskiView Answer on Stackoverflow
Solution 2 - JavascriptIvanView Answer on Stackoverflow
Solution 3 - JavascriptCesarView Answer on Stackoverflow
Solution 4 - JavascriptarufianView Answer on Stackoverflow
Solution 5 - JavascriptAngel PolitisView Answer on Stackoverflow
Solution 6 - Javascript1.21 gigawattsView Answer on Stackoverflow
Solution 7 - JavascriptPaul LeclercView Answer on Stackoverflow
Solution 8 - Javascriptdsmith63View Answer on Stackoverflow
Solution 9 - JavascriptDave FView Answer on Stackoverflow
Solution 10 - JavascriptEntretoizeView Answer on Stackoverflow
Solution 11 - JavascriptdenkdirnixView Answer on Stackoverflow
Solution 12 - JavascriptminigeekView Answer on Stackoverflow
Solution 13 - JavascriptcarinlynchinView Answer on Stackoverflow
Solution 14 - JavascriptWebwomanView Answer on Stackoverflow
Solution 15 - JavascriptMike GashlerView Answer on Stackoverflow
Solution 16 - Javascriptrom mView Answer on Stackoverflow
Solution 17 - JavascriptGaurang TandonView Answer on Stackoverflow
Solution 18 - JavascriptPedro MarthonView Answer on Stackoverflow
Solution 19 - JavascriptVladyslav HrehulView Answer on Stackoverflow
Solution 20 - JavascriptHanna RoseView Answer on Stackoverflow
Solution 21 - JavascriptAllQuestionsAreGoodView Answer on Stackoverflow
Solution 22 - JavascriptkofifusView Answer on Stackoverflow