tl;dr: Finding event handlers registered using jQuery can be tricky. findHandlersJS makes finding them easy, all you need is the event type and a jQuery selector for the elements where the events might originate. Examples can be found here. A working page with findHandlersJS loaded and ready to try can be found here.
Events and event handling are an important part of client-side development. Frequently we are tasked with changing their behavior and part of that process involves locating which methods handle which events. Unfortunately sometimes they can be difficult to locate, especially when we are dealing with a code base that we are not familiar with.
In this blog post I’ll describe an alternative that hopefully makes finding event handlers easier, in particular, event handlers registered using jQuery.
But first let’s look at how we can register an event handler using javascript.
Registering events and event bubbling with plain javascript
You can add event handlers in javascript using the addEventListnerMethod:
Html
<input type="button" id="myButton" value="Click me"/>
<span id="myLabel"></span>
Javascript
document.getElementById('myButton').addEventListener("click", function(event){ //this is the event handler for the click event in myButton document.getElementById('myLabel').innerText=event.target.id + " was clicked"; });
Check it out here
One important thing to be aware about events is that they bubble. What this means is that every element in the hierarchy until the root element of the html will have a chance to handle the event.
Imagine this is describes your html page:
document div p button
You can register an event handler on the button, in the paragraph that contains the button, the div that contains the paragraph or the document itself. They will all “see” the event. This is the reason why it is sometimes difficult to find where the particular event we are interested in is being handled. The next example exhibits the same behaviour as the first:
Html
<input type="button" id="myButton" value="Click me"/>
<span id="myLabel"></span>
Javascript
document.addEventListener("click", function(event){ //this is the event handler for the click event that will be used if you click any element in the page document.getElementById('myLabel').innerText=event.target.id + " was clicked"; });
Try it here
Although this seems to produce the same end result, if you would go look for the event handler in the button itself, you would not find it.
Why would you use this technique then? This technique is popular when parts of the web page are injected via ajax calls. The document object is part of the page’s header object so you can always rely on document being available (which is handy if part of the webpage is going to be fetched sometime in the future), and register your event handlers there.
Registering direct and delegated events using jQuery
With jQuery, event handlers are registered using the .on keyword.
jQuery makes the distinction between event handlers that only handle events triggered in the element they were registered on (direct events handlers) and event handlers that handle events that were triggered in a subset of the children of the element they were registered in (delegate event handlers). The subset of the children is specified through a jQuery selector.
Here’s an example of a direct event handler that handles clicks in a button:
Html
<input type="button" id="myButton" value="Click me"/>
<span id="myLabel"></span>
Javascript
$(function () { $('#myButton').on("click", function (event) { $('#myLabel').text(event.target.id + " was clicked"); }); });
Try it here
Here’s an example of a delegate event handler that handles clicks in all buttons that exist now or that might be added in the future in the whole page:
Delegated events
Html
<input type="button" id="myButton" value="Click me"/>
<span id="myLabel"></span>
Javascript
$(function () { $(document).on("click", ":button", function (event) { $('#myLabel').text(event.target.id + " was clicked"); }); });
Try it here
The best place to find out more about delegate and direct events is the .on documentation page.
Finding event handlers using Chrome dev tools
Browser dev tools help you find event handlers, for example in Chrome you can right click anywhere in the page, for example on a button, and select “Inspect Element”. The event handlers will be shown in the Event Listeners tab (right side of the elements tab).
A very handy feature of the tooling is that you can right click the “handler” and select show function definition:
You can then add breakpoints and debug the event handlers. However if you use events registered with jQuery, you will see jQuery’s event handler. This is because jQuery adds additional functionality to the normal event handlers. This is one of the complicating factors that makes finding the actual event handlers we are interested in more difficult.
If you use findHandlersJS instead you’ll get directly to the actual event handlers.
findHandlersJS (works best in chrome)
The idea is that by specifying an event type (e.g. “click”), and which elements you are interested in, using a jQuery selector, you get all the event handlers that are triggered when you click one of the elements that are covered by the selector you specified.
Here’s an example
Imagine you are working on this web page:
And you want to debug the event handler for the Save button. After you include findHandlersJS you could write in chrome’s console:
findEventHandlers("click", ":button:contains('Save')")
That would provide you with the following information
- element
The actual element where the event handler was registered in - events
Array with information about the jquery event handlers for the event type that we are interested in (e.g. click, change, etc)- handler
Actual event handler method that you can see by right clicking it and selecting Show function definition - selector
The selector provided for delegated events. It will be empty for direct events. - targets
List with the elements that this event handler targets. For example, for a delegated event handler that is registered in the document object and targets all buttons in a page, this property will list all buttons in the page. You can hover them and see them highlighted in chrome.
- handler
You can then hoover over the element property and chrome will highlight the element where the event handler was registered:
You can also hover over function on the handler property and select Show function definition. That will show you the source code for that event handler. You can add breakpoints and debug the event handler method.
More examples:
findEventHandlers(“click”, “div#itemList :button”) would return information about all the jquery event handlers (direct or delegated) that handle a click in the buttons inside a div with id “itemList”.
findEventHandlers(“click”, “*”) returns all click event handlers, including those registered on the document object
findEventHandlers(“change”, document) returns the change event handlers registered on the document object
findEventHandlers(“addNewItem”, “div#items :button:nth(3)”) all event handlers that handle the custom event addNewItem for the the fourth button inside the div with id=”items”
You can get findHandlersJS in github here. You can just copy and paste the raw javascript code to chrome’s console window and just start using it, or if you want to use it in your project just make sure you add it after jQuery (I’ve tested it in versions >= 1.7.1. Might also work with older versions).
Any comments/suggestions are welcomed.