tags:

views:

67

answers:

5

Hi,

I'm looking to add a click handler to a div. But is there a way to use a single click handler function and share it between multiple divs? Since I may have 100 divs, I don't want to create a click handler for each (they'll all practically do the same thing). The jquery example shows:

$("p").click(function () { 
    $(this).foo(); 
});

can we do something like:

$("p").click(myClickHandler);

function myClickHandler(source) {
    source.foo();
}

?

Thanks

+1  A: 

Yes.

There's no need (or ability) to pass a separate source parameter, though. The this object was available in your anonymous function, and so too will it be available in your named function. It will, as always, be the object that was clicked.

function myClickHandler() {
    $(this).foo();
}
VoteyDisciple
Oh, hmm I guess I don't care that it won't be a jquery object at that point - just - what is 'source'? I really just need to get at the object that was clicked (in this case, a <p> element), thank you.
I had misread the original code; I've already edited to use `this`.
VoteyDisciple
+2  A: 

If they are all owned by the same element:

<div id="lol">
<p>blah</p>
<p>slfk</p>
</div>

You can do

$('#lol').click(function(e){

alert( $(e.target).text() );

});

You can apply it to the document too. This way you set the click on 1 element and grab the target. You can add logic to make sure its a paragraph and whatnot too.

This will only use the one function literal and no other functions. Less overhead than .delegate because it does it on the spot instead of internally.

meder
@meder - This is still a good solution. I'd give it +1 if it was complete with the necessary selector check. As it is, it only works if `<p>` elements are the only children of `#lol`. :)
patrick dw
A: 

Yes, you can use the same handler for multiple divs. As shown, this will be set to the element that was clicked, and you can use it however you wish. It will not be passed as an argument, so your second example doesn't work.

$("div.someclass").click(myClickHandler);

function myClickHandler() {
    $(this).foo();
}
Matthew Flaschen
+2  A: 

jQuery's .delegate() method is a great way to go if you don't want the overhead of hundreds of click events.

It assigns one event to a container, which gets fired when the specified descendants of the container get the event.

Test the example: http://jsfiddle.net/jYKgm/

HTML

<div id="container">  // #container has the event handler assigned
    <div>content</div>
    <div>content</div>
    <div>content</div>
    <div>content</div>
    <div>content</div>
    <div>content</div>
</div>​

jQuery

   // The click event handler will fire when <div> elements  
   //   that descend from #container get clicked.
$('#container').delegate('div', 'click', function() {
    alert('index ' + $(this).index() + ' was clicked');
});

This will assign one handler to the #container element, and make it so that any descendant div elements will trigger the handler.

So if there are 500 descendant div elements, they will all share the one event handler.

​ - .delegate() - http://api.jquery.com/delegate

patrick dw
Similar to my answer, +1
meder
Cool, this would have the same low overhead as Matthew Flaschen's solution, right? I mean there is only one function for all divs via element.click(theOneHandler), no additional overhead? Thanks
@user - It will have less memory overhead, since jQuery doesn't need to manage all those separate events on all the elements. If the container is close to the group of elements you're clicking, it can be quite efficient. It is like a more focused version of `live()`, so any elements dynamically added to the container that match the selector (`div` in this case) will fire the handler. IMO, it is definitely the way to go if you have many elements in a container that have the same functionality.
patrick dw
@meder - Thanks for the +. It is similar in the end effect, but is quite different under the hood. Before I stumbled upon `delegate()`, I used to place a handler on a container that had many similar elements, and rely on event bubbling to fire the container's handler. That is exactly what `delegate()` does. With my former way, I had to analyze the `e.target` to make sure the correct element was clicked. `.delegate()` takes care of that, allowing me to simply reference `this`. Much cleaner.
patrick dw
@meder - Oh, I didn't see that you had the `click` event on the container. Yeah, that's just what I used to do. Was a great solution until `delegate()` came around. No more analyzing `e.target` to see what was clicked.
patrick dw
+1 delegate is basically live++ on steroids, and the added selector checks for ensuring that only the correct element gets through is a necessity in almost all cases rather than a privilege.
Anurag
@Anurag - Yeah, if you look at the code, `.delegate()` does nothing more than call `live()`, passing through the selector. http://github.com/jquery/jquery/blob/master/src/event.js#L875 You can do the same exact thing using `live()` directly, passing the root via the `context` parameter.
patrick dw
A: 

Consider this code:

$('div').bind('click', eventHandler);

eventHandler = function () { ... }
tambourine