How to see event listeners list - javascript

I wonder how can I get the list of event listeners for some event?
Suppose I add the event listener to window with this code:
window.addEventListener('click',
function() {
console.log(111);
// a lot of code ...
}, false)
But if I am about to see these listeners with window.onclick it returns null.
However when I click on the window this event handler fires. Can I see this list with another ways?

elem.onclick property and elem.addEventListener('click') do not depend on each other, but the order of attaching listeners really matters
<body>
<span> body stuff </span>
<script>
var element = document.body
element.addEventListener('click', function(){ console.log(1) })
element.onclick = function(){ console.log(2) }
element.addEventListener('click', function(){ console.log(3) })
</script>
</body>
do click on body and get '1 2 3'
then set element.onclick = null
do click on body and get '1 3'
2.1. the property onclick (which can be assigned to only one listener that is a function, not an array) is available from the script for each element (like any other property)
2.2. There is definetely no way to see the event listeners added with addEventListener from the script, however browser integrated debugger will show their state on any breakpoint (or in any given moment).
In Chrome 32+:
F12 -> Pick 'Elements' (Tab) -> Choose <body> element -> On the right pick 'EventListeners'
In other browsers you may need an extension (Dragonfly, Firebug etc.)
2.3. Chrome debugger will show all eventListeners (sorted by event name) for current element and its parents up to the document. But I do not know if it is possible to see the window event listeners.
If you use jQuery, there is a way to get from script a bunch of listeners added only by jQuery, though it's a different story.

Related

Listen for "event removal" in JS / jQuery

I am working with a very large application with a lot of JavaScript. I am trying to determine how I can find the location where a click event is being removed from a specific element.
There is a simple event listener on a specific field added via jQuery (this is an example).
$(document).ready(function() {
$('#id-name').on('click', function(e) {
window.alert('hello');
});
});
If break execution right after this and examine the element in Chrome Inspector, I see the event attached to the element. However, once I continue execution and the page finishes loading, the element no longer has the event. Something is removing it, but I can't find out where this is happening.
Is there a way to listen for "event removal" and trigger code then, so that I can identify where and how this is getting removed? Any other suggestions in locating where the click event is being removed?
Maybe you could override the removeEventListener method and trace it back to see what's calling it.
window.removeEventListener = (type, listener, useCapture)=>console.trace(type, listener, useCapture)

How can I watch Event Handlers being added to an Element?

I've got a bug that looks like it's caused by an Event handler being attached a click event:
mxpnl.track_links("#pagebody a", "Click.body");
I'd like to watch to see how that Element's event handler is added (and when)
I found it in the Chrome Debugger (Dev Tools) > Elements and choose Break on Attribute modifications. Debugger never Breaks.
I also selected it's Parent Div (that it is within) and set Debugger (right-click on Element) > break on subtree modifications. Again, it never breaks.
What am I doing wrong here?
Adding an event listener isn't an attribute change (often) - rather, generally it's a call to addEventListener or an on- assignment. So, listening to attribute changes won't work.
One option would be to monkeypatch addEventListener so that debugger runs when addEventListener is called with the matching arguments. For example:
// snippet might not actually enter the debugger due to embedded sandboxing issues
const nativeEventListener = EventTarget.prototype.addEventListener;
EventTarget.prototype.addEventListener = function(...args) {
if (this.matches('div') && args[0] === 'click') {
console.log('listener is being added to a div');
debugger;
}
nativeEventListener.apply(this, args);
}
// then, when an event listener is added, you'll be able to intercept the call and debug it:
document.querySelector('div').addEventListener('click', () => {
console.log('clicked');
});
<div>click me</div>
In very simple term if explain then event listeners is just a function which add in an array with reference of string such as "click" and "on" etc..
So when you say.....
function myClick1(){
console.log('myclick1 called');
}
document.querySelector('mydiv').addEventListener('click', myClick1);
function myClick2(){
console.log('myclick2 called');
}
document.querySelector('mydiv').addEventListener('click', myClick2);
it add the function myClick1 and myClick2 in event listener array for click and execute in sequence as it added.
AND YOU CAN USE PROTOTYPE OF EVENT TARGET TO MONKEY PATCH THE EVENT LISTENER ARRAY.

Google Chrome Extension Can't See Clicks?

I can't get any of these event listeners to trigger any functions.
The below is in my chrome extension. The alert is triggered but none of the listeners work. The elements are created dynamically so I'm not sure if that makes a difference.
document.addEventListener('DOMContentLoaded', function() {
document.querySelector('.overlay_show').addEventListener('click', alertit);
document.querySelector('.overlay_hide').addEventListener('click', alertit);
});
element html
`<a class='overlay_hide' ><i>Hide<i/></a>`;
`
Any ideas would be helpful?
The elements are created dynamically so I'm not sure if that makes a difference.
It does. If you add the listener before you add the elements, it won't work. When you do document.querySelector('.overlay_show'), it selects the first element that has the class .overlay_show, and adds a listener upon it. Done.
So, you have 2 solutions:
Add the listener after you add the element
But it means that you have to do that each time you do so
Listen for a click on <body> and use e.target
document.body.addEventListener('click', function (e) {
if (e.target.classList.contains('overlay_show')
|| e.target.classList.contains('overlay_hide')) {
alertit()
}
}

How to use getEventListeners in Chrome Dev Tool?

I tried to trace back which function hooked into a click event of .someclass. I open Chrome Dev Tool and type this
getEventListeners(document.querySelector('.someclass'));
The result is this
Object {}
I cannot click and open it to find out the name of the object or the source code that handle click event.
Is there a way to find out?
UPDATE 1:
Followed Krasimir's advise below. There could be only two events: mousemove or mouseover. So how do I find out the exact function handling that event for canvas.overlay? There are just too many to drill down into.
Open the DevTools
Open the Elements tab and locate your element (.someclass)
There are four tabs per element - Styles, Properties, DOM Breakpoints and Event Listeners
Select Event Listeners
You are getting an empty object when calling
getEventListeners(document.querySelector('.someclass'));
probably because the listener isn't hooked up to .someclass element itself (direct event), but to one of it's ancestors (delegated event). There is a good explanation of this here.
You can list both delegated and direct events by calling getEventListeners for specified node and all it's ancestors. This function should do the trick:
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;
}
However, this will output exactly the same thing as the "Event Listeners" tab (with "Filter" option set to "All nodes") that Krasimir mentioned in his answer.
I guess you are using jQuery to bind the events to that element.
That's why you can't see the actual handler code in the drill down menu.
Without wrapped by jQuery, the actual code should be displayed in "listenerBody" like this:

How attach document.click event without touching some element?

I need to click on a document to call some function, but the problem is that when I click on some element that want it doesnt react, so the code:
<body>
<div class="some_element">
some element
</div>
</body>
and js:
$(document).click(function(){
//something to happen
})
and now if I click on the div with class="some_element" the document.click event will be called, but I need to call that event ONLY when I click on the document; or it is possible the make this element an exception?
More detailed:
$('#forma').click(function(e){
e.stopPropagation();
$('#assignment_type_list').slideUp();
})
Lets say #forma - its a parent element of those element, so when I click on the page I want to slideUp someElement and:
$('#assignment_type_select, #assignment_type_label').click(function(){
$('#assignment_type_list').slideToggle();
})
this is the elements when they are clicked the other element is toggled, but the problem is that when I click on this elements the $('#forma').click - also executes, because its parent and the e.stopPropagation() - doesn't help.
All this stopPropagation stuff is right, though this'll cause your script to throw errors on older versions of a certain browser. Guess which one? a cross-browser way:
$('#elem').click(function(e)
{
e = e || window.event;//IE doesn't pass the event object as standard to the handler
//event would normally work, but if you declared some event variable in the current scope
//all falls to pieces, so this e || window.event; thing is to be preferred (IMO)
if (e.stopPropagation)//check if method exists
{
e.stopPropagation();
return;
}
e.cancelBubble = true;//for IE
});
However, you wanted to check if the element that was actually clicked, is the one you need. The problem with that is, that the way the event is passed through the DOM. In W3C browsers the event is first passed to the document, and then clambers down to the element that was actually clicked (propagates through the dom). By contrast IE dispatches its events on the element itself, and then sends it up to the document (except for the change event triggered by select elements... to add insult to injury). What this effectively means is that a click event that is registered in to body element in W3C browsers might be on its way to a checkbox of sorts, or it could be a click inside an empty div. Again, in IE, when a click event reaches the body tag, it could have been dispatched too any element on the page. So it may prove useful in your case to google: event delegation, or turn to jQuery's .delegate() method.
Or check the event object to see if the event is allowed to propagate through or not:
var target = e.target || e.srcElement;//target now holds a reference to the clicked element
The property names neatly show the difference between the bubbling model and the propagating one: in the first case (srcElement), the event is coming from a source element in the dom. In the W3C propagating model, the event is cought while it's headed for a target element somewhere in the dom. Look at it like a heat-seeking missile (w3c) versus a shower of debris after the target was shot down (IE, always the destructive one, and in this case often to late to respond to the events, and therefore to late to handle them:P)
One way to do it is to check for the event's target.
$('html').click(function(event){
if (event.target != this){
}else{
//do stuff
}
});
Here's a working fiddle
Elements on the document are part of the document, so if you click "some_element" in the document, it is obvious that event registered on document will be fired/triggered. If you dont want to execute code which was for "document" then first get the element OR "event source" which originates this event, and check if it was "some_element" in your question above.

Categories