Get event listeners attached to node using addEventListener

JavascriptDom Events

Javascript Problem Overview


I have already looked at these questions:

however none of them answers how to get a list of event listeners attached to a node using addEventListener, without modifying the addEventListener prototype before the event listeners are created.

VisualEvent doesn't display all event listener (iphone specific ones) and I want to do this (somewhat) programmatically.

Javascript Solutions


Solution 1 - Javascript

Chrome DevTools, Safari Inspector and Firebug support getEventListeners(node).

getEventListeners(document)

Solution 2 - Javascript

You can't.

The only way to get a list of all event listeners attached to a node is to intercept the listener attachment call.

DOM4 addEventListener

Says

> Append an event listener to the associated list of event listeners with type set to type, listener set to listener, and capture set to capture, unless there already is an event listener in that list with the same type, listener, and capture.

Meaning that an event listener is added to the "list of event listeners". That's all. There is no notion of what this list should be nor how you should access it.

Solution 3 - Javascript

Since there is no native way to do this ,Here is the less intrusive solution i found (dont add any 'old' prototype methods):

var ListenerTracker=new function(){
	var targets=[];
	// listener tracking datas
	var _elements_  =[];
	var _listeners_ =[];
	this.init=function(){
		this.listen(Element,window);
	};
	this.listen=function(){
		for(var i=0;i<arguments.length;i++){
			if(targets.indexOf(arguments[i])===-1){
				targets.push(arguments[i]);//avoid duplicate call
				intercep_events_listeners(arguments[i]);
			}
		}
	};
	// register individual element an returns its corresponding listeners
	var register_element=function(element){
		if(_elements_.indexOf(element)==-1){
			// NB : split by useCapture to make listener easier to find when removing
			var elt_listeners=[{/*useCapture=false*/},{/*useCapture=true*/}];
			_elements_.push(element);
			_listeners_.push(elt_listeners);
		}
		return _listeners_[_elements_.indexOf(element)];
	};
	var intercep_events_listeners = function(target){
		var _target=target;
		if(target.prototype)_target=target.prototype;
		if(_target.getEventListeners)return;
		if(typeof(_target.addEventListener)!=='function'||typeof(_target.removeEventListener)!=='function'){
			console.log('target=',target);
			throw('\nListenerTracker Error:\nUnwrappable target.');
		}
		// backup overrided methods
		var _super_={
			"addEventListener"      : _target.addEventListener,
			"removeEventListener"   : _target.removeEventListener
		};

		_target["addEventListener"]=function(type, listener, useCapture){
			var listeners=register_element(this);
			// add event before to avoid registering if an error is thrown
			_super_["addEventListener"].apply(this,arguments);
			// adapt to 'elt_listeners' index
			var uc=(typeof(useCapture)==='object'?useCapture.useCapture:useCapture)?1:0;
			if(!listeners[uc][type])listeners[uc][type]=[];
			listeners[uc][type].push({cb:listener,args:arguments});
		};
		_target["removeEventListener"]=function(type, listener, useCapture){
			var listeners=register_element(this);
			// add event before to avoid registering if an error is thrown
			_super_["removeEventListener"].apply(this,arguments);
			// adapt to 'elt_listeners' index
			useCapture=(typeof(useCapture)==='object'?useCapture.useCapture:useCapture)?1:0;
			if(!listeners[useCapture][type])return;
			var lid = listeners[useCapture][type].findIndex(obj=>obj.cb===listener);
			if(lid>-1)listeners[useCapture][type].splice(lid,1);
		};
		_target["getEventListeners"]=function(type){
			var listeners=register_element(this);
			// convert to listener datas list
			var result=[];
			for(var useCapture=0,list;list=listeners[useCapture];useCapture++){
				if(typeof(type)=="string"){// filtered by type
					if(list[type]){
						for(var id in list[type]){
							result.push({
								"type":type,
								"listener":list[type][id].cb,
								"args":list[type][id].args,
								"useCapture":!!useCapture
							});
						}
					}
				}else{// all
					for(var _type in list){
						for(var id in list[_type]){
							result.push({
								"type":_type,
								"listener":list[_type][id].cb,
								"args":list[_type][id].args,
								"useCapture":!!useCapture
							});
						}
					}
				}
			}
			return result;
		};
	};

}();


ListenerTracker.init();

EDIT

Suggestion from @mplungjan: modified to listen to wrappable targets (singleton|constructor). 'init' tracks Element and window .

exemple with other wrappable target:

ListenerTracker.listen(XMLHttpRequest);

Suggestion from @kodfire : You may get optionals arguments with the args property.

Solution 4 - Javascript

I can't find a way to do this with code, but in stock Firefox 64, events are listed next to each HTML entity in the Developer Tools Inspector as noted on MDN's Examine Event Listeners page and as demonstrated in this image:

screen shot of FF Inspector

Solution 5 - Javascript

You can obtain all jQuery events using $._data($('[selector]')[0],'events'); change [selector] to what you need.

There is a plugin that gather all events attached by jQuery called eventsReport.

Also i write my own plugin that do this with better formatting.

But anyway it seems we can't gather events added by addEventListener method. May be we can wrap addEventListener call to store events added after our wrap call.

It seems the best way to see events added to an element with dev tools.

But you will not see delegated events there. So there we need jQuery eventsReport.

UPDATE: NOW We CAN see events added by addEventListener method SEE RIGHT ANSWER TO THIS QUESTION.

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
QuestionTyiloView Question on Stackoverflow
Solution 1 - JavascriptNVIView Answer on Stackoverflow
Solution 2 - JavascriptRaynosView Answer on Stackoverflow
Solution 3 - JavascriptyorgView Answer on Stackoverflow
Solution 4 - JavascriptAdam KatzView Answer on Stackoverflow
Solution 5 - JavascriptRantievView Answer on Stackoverflow