Can I find events bound on an element with jQuery? - javascript

I bind two event handlers on this link:
<a href='#' id='elm'>Show Alert</a>
JavaScript:
$(function()
{
$('#elm').click(_f);
$('#elm').mouseover(_m);
});
function _f(){alert('clicked');}
function _m(){alert('mouse over');}
Is there any way to get a list of all events bound on an element, in this case on element with id="elm"?

In modern versions of jQuery, you would use the $._data method to find any events attached by jQuery to the element in question. Note, this is an internal-use only method:
// Bind up a couple of event handlers
$("#foo").on({
click: function(){ alert("Hello") },
mouseout: function(){ alert("World") }
});
// Lookup events for this particular Element
$._data( $("#foo")[0], "events" );
The result from $._data will be an object that contains both of the events we set (pictured below with the mouseout property expanded):
Then in Chrome, you may right click the handler function and click "view function definition" to show you the exact spot where it is defined in your code.

General case:
Hit F12 to open Dev Tools
Click the Sources tab
On right-hand side, scroll down to Event Listener Breakpoints, and expand tree
Click on the events you want to listen for.
Interact with the target element, if they fire you will get a break point in the debugger
Similarly, you can:
right click on the target element -> select "Inspect element"
Scroll down on the right side of the dev frame, at the bottom is 'event listeners'.
Expand the tree to see what events are attached to the element. Not sure if this works for events that are handled through bubbling (I'm guessing not)

I'm adding this for posterity; There's an easier way that doesn't involve writing more JS. Using the amazing firebug addon for firefox,
Right click on the element and select 'Inspect element with Firebug'
In the sidebar panels (shown in the screenshot), navigate to the events tab using the tiny > arrow
The events tab shows the events and corresponding functions for each event
The text next to it shows the function location

You can now simply get a list of event listeners bound to an object by using the javascript function getEventListeners().
For example type the following in the dev tools console:
// Get all event listners bound to the document object
getEventListeners(document);

The jQuery Audit plugin plugin should let you do this through the normal Chrome Dev Tools. It's not perfect, but it should let you see the actual handler bound to the element/event and not just the generic jQuery handler.

While this isn't exactly specific to jQuery selectors/objects, in FireFox Quantum 58.x, you can find event handlers on an element using the Dev tools:
Right-click the element
In the context menu, Click 'Inspect Element'
If there is an 'ev' icon next to the element (yellow box), click on 'ev' icon
Displays all events for that element and event handler

Note that events may be attached to the document itself rather than the element in question. In that case, you'll want to use:
$._data( $(document)[0], "events" );
And find the event with the correct selector:
And then look at the handler > [[FunctionLocation]]

I used something like this if($._data($("a.wine-item-link")[0]).events == null) { ... do something, pretty much bind their event handlers again } to check if my element is bound to any event. It will still say undefined (null) if you have unattached all your event handlers from that element. That is the reason why I am evaluating this in an if expression.

When I pass a little complex DOM query to $._data like this: $._data($('#outerWrap .innerWrap ul li:last a'), 'events') it throws undefined in the browser console.
So I had to use $._data on the parent div: $._data($('#outerWrap')[0], 'events') to see the events for the a tags. Here is a JSFiddle for the same: http://jsfiddle.net/giri_jeedigunta/MLcpT/4/

Related

Why I can't see onclick property?

When I was exploring StackOverflow's code, I get:
And I tried to get onclick event handler. There are the report:
> $0.onclick
< null
> $0.parentElement.onclick
< null
But $0.click() gives me some result (answer is upvoted).
How StackOverflow developers hid it and how to make it by hand, in pure JS?
While the .onclick property is one way to add a click event listener to elements, it's not the only way. Another way is via .addEventListener(). When an event listener is added to an element via .addEventListener(), the onclick attribute/property doesn't update to the event handler function. The .onclick property is only set on an element if you're using the onclick="" attribute or if the code has set the property elem.onclick = function() {...}, which nowdays isn't very often.
Chrome does provide you with a way to find the event handlers on different elements. When you're in your developer tools, you can select the element you're interested in, click "Event Listeners" in the right-hand pane, find the event you're intrested in, in this case that's the "click" event, and then look for your element:
Your element happens to have an event associated with it, but this might not always be the case. As the comments on your question have pointed out, you can sometimes run into cases where there is no click event handler on your specific element, but rather, it is added to a parent of that element. In this case, when you click on your element, the event propegates/"bubbles" up through the DOM, eventually reaching your parent element with the click event listener. The event handler on the parent can then see what element was originally clicked, and can then perform some actions based on that. This is known as event delegation, and is one of the reasons why you might not always find an event tied to your element even when looking in dev tools.

How to check if an element has an event or not? [duplicate]

I bind two event handlers on this link:
<a href='#' id='elm'>Show Alert</a>
JavaScript:
$(function()
{
$('#elm').click(_f);
$('#elm').mouseover(_m);
});
function _f(){alert('clicked');}
function _m(){alert('mouse over');}
Is there any way to get a list of all events bound on an element, in this case on element with id="elm"?
In modern versions of jQuery, you would use the $._data method to find any events attached by jQuery to the element in question. Note, this is an internal-use only method:
// Bind up a couple of event handlers
$("#foo").on({
click: function(){ alert("Hello") },
mouseout: function(){ alert("World") }
});
// Lookup events for this particular Element
$._data( $("#foo")[0], "events" );
The result from $._data will be an object that contains both of the events we set (pictured below with the mouseout property expanded):
Then in Chrome, you may right click the handler function and click "view function definition" to show you the exact spot where it is defined in your code.
General case:
Hit F12 to open Dev Tools
Click the Sources tab
On right-hand side, scroll down to Event Listener Breakpoints, and expand tree
Click on the events you want to listen for.
Interact with the target element, if they fire you will get a break point in the debugger
Similarly, you can:
right click on the target element -> select "Inspect element"
Scroll down on the right side of the dev frame, at the bottom is 'event listeners'.
Expand the tree to see what events are attached to the element. Not sure if this works for events that are handled through bubbling (I'm guessing not)
I'm adding this for posterity; There's an easier way that doesn't involve writing more JS. Using the amazing firebug addon for firefox,
Right click on the element and select 'Inspect element with Firebug'
In the sidebar panels (shown in the screenshot), navigate to the events tab using the tiny > arrow
The events tab shows the events and corresponding functions for each event
The text next to it shows the function location
You can now simply get a list of event listeners bound to an object by using the javascript function getEventListeners().
For example type the following in the dev tools console:
// Get all event listners bound to the document object
getEventListeners(document);
The jQuery Audit plugin plugin should let you do this through the normal Chrome Dev Tools. It's not perfect, but it should let you see the actual handler bound to the element/event and not just the generic jQuery handler.
While this isn't exactly specific to jQuery selectors/objects, in FireFox Quantum 58.x, you can find event handlers on an element using the Dev tools:
Right-click the element
In the context menu, Click 'Inspect Element'
If there is an 'ev' icon next to the element (yellow box), click on 'ev' icon
Displays all events for that element and event handler
Note that events may be attached to the document itself rather than the element in question. In that case, you'll want to use:
$._data( $(document)[0], "events" );
And find the event with the correct selector:
And then look at the handler > [[FunctionLocation]]
I used something like this if($._data($("a.wine-item-link")[0]).events == null) { ... do something, pretty much bind their event handlers again } to check if my element is bound to any event. It will still say undefined (null) if you have unattached all your event handlers from that element. That is the reason why I am evaluating this in an if expression.
When I pass a little complex DOM query to $._data like this: $._data($('#outerWrap .innerWrap ul li:last a'), 'events') it throws undefined in the browser console.
So I had to use $._data on the parent div: $._data($('#outerWrap')[0], 'events') to see the events for the a tags. Here is a JSFiddle for the same: http://jsfiddle.net/giri_jeedigunta/MLcpT/4/

Inspect attached event handlers for any DOM element

Is there any way to view what functions / code are attached to any event for a DOM element? Using Firebug or any other tool.
The Elements Panel in Google Chrome Developer tools has had this since Chrome releases in mid 2011 and Chrome developer channel releases since 2010.
Also, the event listeners shown for the selected node are in the order in which they are fired through the capturing and bubbling phases.
Hit command + option + i on Mac OSX and Ctrl + Shift + i on Windows to fire this up in Chrome
Event handlers attached using traditional element.onclick= handler or HTML <element onclick="handler"> can be retrieved trivially from the element.onclick property from script or in-debugger.
Event handlers attached using DOM Level 2 Events addEventListener methods and IE's attachEvent cannot currently be retrieved from script at all. DOM Level 3 once proposed element.eventListenerList to get all listeners, but it is unclear whether this will make it to the final specification. There is no implementation in any browser today.
A debugging tool as browser extension could get access to these kinds of listeners, but I'm not aware of any that actually do.
Some JS frameworks leave enough of a record of event binding to work out what they've been up to. Visual Event takes this approach to discover listeners registered through a few popular frameworks.
Chrome Dev Tools recently announced some new tools for Monitoring JavaScript Events.
TL;DR
Listen to events of a certain type using monitorEvents().
Use unmonitorEvents() to stop listening.
Get listeners of a DOM element using getEventListeners().
Use the Event Listeners Inspector panel to get information on event listeners.
Finding Custom Events
For my need, discovering custom JS events in 3rd party code, the following two versions of the getEventListeners() were amazingly helpful;
getEventListeners(window)
getEventListeners(document)
If you know what DOM Node the event listener was attached to you'd pass that instead of window or document.
Known Event
If you know what event you wish to monitor e.g. click on the document body you could use the following: monitorEvents(document.body, 'click');.
You should now start seeing all the click events on the document.body being logged in the console.
You can view directly attached events (element.onclick = handler) by looking at the DOM.
You can view jQuery-attached events in Firefox using FireBug with FireQuery. There doesn't appear to be any way to see addEventListener-added events using FireBug. However, you can see them in Chrome using the Chrome debugger.
You can use Visual Event by Allan Jardine to inspect all the currently attached event handlers from several major JavaScript libraries on your page. It works with jQuery, YUI and several others.
Visual Event is a JavaScript bookmarklet so is compatible with all major browsers.
You can extend your javascript environment to keep track of event listeners. Wrap (or 'overload') the native addEventListener() method with some code that cans keep a record of any event listener added from then onwards. You'd also have to extend HTMLElement.prototype.removeEventListener to keep records that accurately reflect what is happening in the DOM.
Just for the sake of illustration (untested code) - this is an example of how you would 'wrap' addEventListener to have records of the registered event listeners on object itself:
var nativeMethod = HTMLElement.prototype.addEventListener;
HTMLElement.prototype.addEventListener = function (type, listener) {
var el = e.currentTarget;
if(!(el.eventListeners instanceof Array)) { el.eventListeners = []}
el.eventListeners.push({'type':type, 'listener':listener});
nativeMethod.call(el, type, listener);
}
I was curious whether #Rolf's approach would actually work. Remember, it is a "crude" way of replacing the standard HTMLElement.prototype.addEventLister() with a wrapped version of the same. Obviously this can only be an "injection method for testing" and would definitely have to be removed for anything approaching the "production version".
When tesing it I found out that, apart from a minor glitch (his e was not defined anywhere but could easily be replaced by a this) the approach does work, as long as
you are consistently working with addEventListener() only on the actual elements themselves
and if you do not use delegated event attachment
or direct event assignments by setting attributes like onclick or oninput.
I went on to find out whether the "sniffing" could be made a little more universal and came up with the following modified version:
(nativeMethod=>{ // IIFE-closure to manipulate the standard addEventListener method:
HTMLElement.prototype.addEventListener = function (type,fun) {
(this.ELL=this.ELL||[]).push([type,fun]);
nativeMethod.call(this,type,fun);
}
})(HTMLElement.prototype.addEventListener);
// LIST direct and indirect event attachments for element `el`:
function listELfor(el){
const events="click,change,input,keyup,keydown,blur,focus,mouseover,mouseout"
.split(",").map(e=>"on"+e); // possible direct event assignments to check up on
const evlist = (el.ELL||[]).map(([t,f])=>[t,f.toString()]);
events.forEach(e=> el[e] && (evlist[e]=[e.substr(2),el[e].toString()]) )
let p=el.parentNode;
if (p.tagName!=="HTML"){ // if available: run function on parent level recursively:
evlist[p.tagName+(p.id?'#'+p.id:'')+(p.className?'.'+p.className:'')]=listELfor(el.parentNode);
}
return evlist;
};
// ============ TESTING ==========================================
// now, let's do some sample event attachments in different ways:
const sp=document.querySelector('h1 span'); // sp = the target SPAN within H1
sp.addEventListener('click',function(e){console.log('first:',e.target)});
sp.addEventListener('click',function(e){console.log('second:',e.target.tagName)});
sp.addEventListener('click',function(e){console.log('third:',e.target.dataset.val)});
// attach an event to the parent node (H1):
sp.parentNode.addEventListener('click',function(e){console.log('Click event attached to H1, click-target is',e.target.tagName);});
// and finally, let's also assign an onclick event directly by using the ONCLICK attribute:
sp.onclick=e=>console.log('direct onclick on span, text:',e.target.textContent);
// Get all event handler functions linked to `sp`?
const allHandlers=listELfor(sp);
for (id in allHandlers) console.log(id,allHandlers[id]);
h1 span {cursor:pointer}
.as-console-wrapper {max-height:85% !important}
<div id="main-frame-error" class="interstitial-wrapper">
<div id="main-content">
<div class=""></div>
<div id="main-message">
<h1>Hello, <span data-val="123">THESE WORDS ARE CLICKABLE</span></h1>
<p>Some more text here to pad it out. This text should be unresponsive.</p>
</div>
</div>
</div>
The IIFE structure captures .addEventListener() function handler attachments as an array store in the ELL attribute of the concerned DOM element. The function listELfor(el) then picks up these function handlers of the element itself and walk up the parent hierarchy to also get assignments to its parents. The function will also take care of direct event assignments using onclick and similar attributes.
listELfor() will return an array object with extra properties. These properties will not necessarily be visible in a plain console.log(). This is the reason why I used the for (id in allHandlers) loop.
Please note:
Chrome will list these "extra" Array attributes too - and even further properties, relating to the parent's and their parent's parent's event attachments, like shown below:

How to debug JavaScript / jQuery event bindings with Firebug or similar tools?

I need to debug a web application that uses jQuery to do some fairly complex and messy DOM manipulation. At one point, some of the events that were bound to particular elements, are not fired and simply stop working.
If I had a capability to edit the application source, I would drill down and add a bunch of Firebug console.log() statements and comment/uncomment pieces of code to try to pinpoint the problem. But let's assume I cannot edit the application code and need to work entirely in Firefox using Firebug or similar tools.
Firebug is very good at letting me navigate and manipulate the DOM. So far, though, I have not been able to figure out how to do event debugging with Firebug. Specifically, I just want to see a list of event handlers bound to a particular element at a given time (using Firebug JavaScript breakpoints to trace the changes). But either Firebug does not have the capability to see bound events, or I'm too dumb to find it. :-)
Any recommendations or ideas? Ideally, I would just like to see and edit events bound to elements, similarly to how I can edit DOM today.
See How to find event listeners on a DOM node.
In a nutshell, assuming at some point an event handler is attached to your element (eg): $('#foo').click(function() { console.log('clicked!') });
You inspect it like so:
jQuery 1.3.x
var clickEvents = $('#foo').data("events").click;
jQuery.each(clickEvents, function(key, value) {
console.log(value) // prints "function() { console.log('clicked!') }"
})
jQuery 1.4.x
var clickEvents = $('#foo').data("events").click;
jQuery.each(clickEvents, function(key, handlerObj) {
console.log(handlerObj.handler) // prints "function() { console.log('clicked!') }"
})
See jQuery.fn.data (where jQuery stores your handler internally).
jQuery 1.8.x
var clickEvents = $._data($('#foo')[0], "events").click;
jQuery.each(clickEvents, function(key, handlerObj) {
console.log(handlerObj.handler) // prints "function() { console.log('clicked!') }"
})
There's a nice bookmarklet called Visual Event that can show you all the events attached to an element. It has color-coded highlights for different types of events (mouse, keyboard, etc.). When you hover over them, it shows the body of the event handler, how it was attached, and the file/line number (on WebKit and Opera). You can also trigger the event manually.
It can't find every event because there's no standard way to look up what event handlers are attached to an element, but it works with popular libraries like jQuery, Prototype, MooTools, YUI, etc.
You could use FireQuery. It shows any events attached to DOM elements in the Firebug's HTML tab. It also shows any data attached to the elements through $.data.
Here's a plugin which can list all event handlers for any given element/event:
$.fn.listHandlers = function(events, outputFunction) {
return this.each(function(i){
var elem = this,
dEvents = $(this).data('events');
if (!dEvents) {return;}
$.each(dEvents, function(name, handler){
if((new RegExp('^(' + (events === '*' ? '.+' : events.replace(',','|').replace(/^on/i,'')) + ')$' ,'i')).test(name)) {
$.each(handler, function(i,handler){
outputFunction(elem, '\n' + i + ': [' + name + '] : ' + handler );
});
}
});
});
};
Use it like this:
// List all onclick handlers of all anchor elements:
$('a').listHandlers('onclick', console.info);
// List all handlers for all events of all elements:
$('*').listHandlers('*', console.info);
// Write a custom output function:
$('#whatever').listHandlers('click',function(element,data){
$('body').prepend('<br />' + element.nodeName + ': <br /><pre>' + data + '<\/pre>');
});
Src: (my blog) -> http://james.padolsey.com/javascript/debug-jquery-events-with-listhandlers/
The WebKit Developer Console (found in Chrome, Safari, etc.) lets you view attached events for elements.
More detail in this Stack Overflow question
Use $._data(htmlElement, "events") in jquery 1.7+;
ex:
$._data(document, "events") or $._data($('.class_name').get(0), "events")
As a colleague suggested, console.log > alert:
var clickEvents = $('#foo').data("events").click;
jQuery.each(clickEvents, function(key, value) {
console.log(value);
})
jQuery stores events in the following:
$("a#somefoo").data("events")
Doing a console.log($("a#somefoo").data("events")) should list the events attached to that element.
Using DevTools in the latest Chrome (v29) I find these two tips very helpful for debugging events:
Listing jQuery events of the last selected DOM element
Inspect an element on the page
type the following in the console:
$._data($0, "events") //assuming jQuery 1.7+
It will list all jQuery event objects associated with it, expand the interested event, right-click on the function of the "handler" property and choose "Show function definition". It will open the file containing the specified function.
Utilizing the monitorEvents() command
ev icon next to elements
Within the Firefox Developer Tools' Inspector panel lists all events bound to an element.
First select an element with Ctrl + Shift + C, e.g. Stack Overflow's upvote arrow.
Click on the ev icon to the right of the element, and a dialogue opens:
Click on the pause sign || symbol for the event you want, and this opens the debugger on the line of the handler.
You can now place a breakpoint there as usual in the debugger, by clicking on the left margin of the line.
This is mentioned at: https://developer.mozilla.org/en-US/docs/Tools/Page_Inspector/How_to/Examine_event_listeners
Unfortunately, I couldn't find a way for this to play nicely with prettyfication, it just seems to open at the minified line: How to beautify Javascript and CSS in Firefox / Firebug?
Tested on Firefox 42.
Looks like FireBug crew is working on an EventBug extension. It will add another panel to FireBug - Events.
"The events panel will list all of the event handlers on the page grouped by event type. For each event type you can open up to see the elements the listeners are bound to and summary of the function source." EventBug Rising
Although they cannot say right now when it will be released.
I also found jQuery Debugger in the chrome store. You can click on a dom item and it will show all events bound to it along with the callback function. I was debugging an application where events weren't being removed properly and this helped me track it down in minutes. Obviously this is for chrome though, not firefox.
According to this thread, there is no way in Firebug to view what events are attached to listeners on a DOM element.
It looks like the best you can do is either what tj111 suggests, or you could right-click the element in the HTML viewer, and click "Log Events" so you can see which events are firing for a particular DOM element. I suppose one could do that to see what events could be firing off particular functions.
With version 2.0 Firebug introduced an Events panel, which lists all events for the element currently selected within the HTML panel.
It can also display event listeners wrapped into jQuery event bindings in case the option Show Wrapped Listeners is checked, which you can reach via the Events panel's options menu.
With that panel the workflow to debug an event handler is as follows:
Select the element with the event listener you want to debug
Inside the Events side panel right-click the function under the related event and choose Set Breakpoint
Trigger the event
=> The script execution will stop at the first line of the event handler function and you can step debug it.
Firebug 2 does now incorporate DOM events debugging / inspection.

Locating an element in a 'Facebox' box

Heres my link:
http://tinyurl.com/6j727e
If you click on the link in test.php, it opens in a modal box which is using the jquery 'facebox' script.
I'm trying to act upon a click event in this box, and if you view source of test.php you'll see where I'm trying to loacte the link within the modal box.
$('#facebox .hero-link').click(alert('click!'));
However, it doesn't detect a click and oddly enough the click event runs when the page loads.
The close button DOES however have a click event built in that closes the box, and I suspect my home-grown click event is being prevented somehow, but I can't figure it out.
Can anyone help? Typically its the very last part of a project and its holding me up, as is always the way ;)
First, the reason you're getting the alert on document load is because the #click method takes a function as an argument. Instead, you passed it the return value of alert, which immediately shows the alert dialog and returns null.
The reason the event binding isn't working is because at the time of document load, #facebox .hero-link does not yet exist. I think you have two options that will help you fix this.
Option 1) Bind the click event only after the facebox is revealed. Something like:
$(document).bind('reveal.facebox', function() {
$('#facebox .hero-link').click(function() { alert('click!'); });
});
Option 2) Look into using the jQuery Live Query Plugin
Live Query utilizes the power of jQuery selectors by binding events or firing callbacks for matched elements auto-magically, even after the page has been loaded and the DOM updated.
jQuery Live Query will automatically bind the click event when it recognizes that Facebox modified the DOM. You should then only need to write this:
$('#facebox .hero-link').click(function() { alert('click!'); });
Alternatively use event delegation
This basically hooks events to containers rather than every element and queries the event.target in the container event.
It has multiple benefits in that you reduce the code noise (no need to rebind) it also is easier on browser memory (less events bound in the dom)
Quick example here
jQuery plugin for easy event delegation
P.S event delegation is pencilled to be in the next release (1.3) coming very soon.

Categories

Resources