views:

89

answers:

4

Hypothetical: I find a page with a button ('#bigButton'), that when clicked causes a llama ('img#theLlama') to show() using jQuery.

So, somewhere (say, Line 76) in buttons.js:

$('#bigButton').click(function(){
$('img#theLlama').show();
})

Now, let's say I have a big HTML page with a whole bunch of .js files included. I can click on the button and see the llama appear, but I have no idea where the code above is.

The solution I am looking for is very similar to that which is available with CSS in Firebug. I want to inspect the element and have it show me that this jQuery occurs in Line 76 of buttons.js, along with any other bindings on this element.

*Note: The bounty is for a specific answer to the 'llama question,' ie pointing to a the solution that is described above. *

FireQuery is a great tool for many jQuery tasks, but it does not seem to answer the llama question. If I am wrong about this, please correct me.

+3  A: 

Given the interface you're after, I think you'll want FireQuery: http://firequery.binaryage.com/

It's a Firebug addon specifically for areas like this (a jQuery specific addon, strong in data/events).

Nick Craver
Beautiful addon! Let me just add that Firebugs ability to set breakpoints in JS code helps a lot debugging these sort of things.
moontear
Yes, FireQuery is great and already in my toolbox. However, it doesn't seem to answer the llama question. Or does it and I'm not seeing it?
Justin Myles Holmes
@Justin - You can see the event on `#bigButton` and view it's handler code...but you're not going to be able to see where it was bound most times, since that can vary quite a bit. Or alternatively, go to the console: `$("#bigButton").data("events")` to see all handlers, the console interface makes it pretty easy to navigate the object.
Nick Craver
@moontear, the handlers are stored in .data("events") and FireQuery makes it easy to view these data objects. You can verify this in the console by doing $("#bigButton").data("events") and looking at the object returned which would contain an array for click handlers.
rchern
@rchern, @Nick Craver - executing $("#bigButton").data("events") in the console returns { click=undefined }. Although I can examine this further in the DOM tab, it does not give me a way to see where the initial binding is.
Justin Myles Holmes
@Justin - Finding that is *very* tricky, not something that can be automated, you're better off doing a search in the source for that, much less time spent overall.
Nick Craver
@Nick Craver: That's what I suspected. Which brings me to my last point: Weren't we better off (at least in this aspect) with the onClick attribute?
Justin Myles Holmes
@Nick Craver: Also, why can't it be automated? The browser knows what to do (ie, display the llama) - why can't it simply tell me *why* it showed the llama?
Justin Myles Holmes
@Justin - Not really, there are many disadvantages, for example I can use one line of code cached by the client in another file to bind any number of elements...there are *tremendous* advantages to the client. Is it harder to debug? well maybe, but not knowing where your code is/what it does is a different problem that "how do we make the best user experience?", what's better for one may not be necessarily better for the other. I think once you find what's going on here, take a look at how your script is organized, see if you can make finding this *much* easier in the future.
Nick Craver
@Justin - There could be 20 handlers, bound in 20 places, bound, rebound unbound, maybe bound to a parent off a bubble, what if it's variable based, what if it's `.live()` with no click handler at all? Is it a user triggered event or simulated? There are tons of variables here, you have to remember that JavaScript engines trace code to make it much *faster*, not easier to debug...the browser wants to bind the event handlers as fast as possible to beat the other guy, not make the events easier to trace, which is inherently heavier.
Nick Craver
@Nick Craver: In regular operations, I don't expect the browser to stress about these questions. However, for the purposes of inspecting the code, this seems essential to me. It'd be great if firequery (or eventbug) did this, even if it slowed the rendering of the page way down while doing it.
Justin Myles Holmes
And of course it's no problem in cases where I wrote the script, but when it's somebody else's script and there are dozens of js files included, it's awful to have to search through all of them every time I want to locate an event binding.
Justin Myles Holmes
@Justin - I don't disagree that it'd be handy, and they may improve the tools to do so in the future. My point was it's not an easy question to answer...or FireQuery would have that as feature #1 :)
Nick Craver
A: 

FireQuery is the most convenient, but if you need to do it manually, you can get a reference to the click handling function with $(element).data('events').click[0].handler (of course it is not necessarily 0 if there are multiple click handlers). From there it is up to your favorite debugger to locate that function in the code. (Using named functions helps. Firebug can sometimes locate anonymous functions, but more often not. It will show the body of the function though, if you hover above it with the mouse.)

Update this is how data is shown with FireQuery:

HTML view:

jQuery data in Firebug HTML view

console:

jQuery data in Firebug console

Tgr
Of course, thanks to the wonders of event bubbling, clicking on button can activate an event handler on any parent element. If there are many of those, Firebug's profiling is your friend.
Tgr
@Tgr: But FireQuery doesn't allow me to directly answer the llama question, right? I don't see where in FireQuery I am able to inspect an element and see what events are bound to it.
Justin Myles Holmes
@Justin Myles Holmes: In the HTML view, it will show what data is bound to each node; you can just check the object bound as "events" in the DOM view and look at its handler property. The console also shows if there is data associated to a logged jQuery object, with the small envelope(?) icon before the closing bracket. See the images I added to my answer.
Tgr
I see the "events=Object{ click = }" - but I need to know exactly what comes after the =. How can I find the place in the .js file where the click event is defined?
Justin Myles Holmes
@Justin Myles Holmes: just click on the "events=" box to inspect it.
Tgr
A: 

Well eventbug will show you all of the event handlers for an element, http://getfirebug.com/releases/eventbug but often the handler is some generic code.

johnjbarton
I have looked at eventbug and it seems to just take me to the same information presented in the DOM tab. It doesn't seem to answer the llama question. If I'm wrong, please let me know. I really appreciate the suggestion. :-)
Justin Myles Holmes
Ok: You're wrong! Actually there is no way to tell if you're wrong or not because you have not posted a test case. So I can't help you.
johnjbarton
What can I add to my question for it to qualify as a "test case"?
Justin Myles Holmes
some HTML and the script tag(s) for jQuery. What is bigButton and theLlama?
johnjbarton
+1  A: 

Using Firebug, FireQuery and this fiddle:

Hitting Cmd+Shift+C (Inspect Element) and clicking on the button reveals this: Screenshot 1

Clicking on the events Object {click= } reveals this (after expanding some info)

Screenshot 2

And clicking on the function() reveals this:
Screenshot 3

Which should be the code you are looking for, right?

As a note, Firebug can't always find the exact line of code something came from. I've had this method fail completely! Another approach is to use named function expressions. Changing the code to:

$('#bigButton').click(function showMyLlama(){
  $('img#theLlama').show();
})

Now reveals this when inspecting the events object:

alt text

Which is way more useful than just function() as it is now obvious that this handler shows us a llama. You can also now search the code for the function name and find it!

gnarf
Awesome. The single best answer I have ever seen on StackOverflow. You win.
Justin Myles Holmes