views:

182

answers:

2

When a user clicks on a <li>-element or on a child element of it, I want to add a class to this <li>-element.

This works fine, but for performance enhancement I decided to bind this event to the <ul>-element, so unbinding and binding this event is much faster in a list consisting of 1000 <li>-elements. The only change I thought I had to make was to replace this with event.target BUT event.target can also refer to a child element of a list item or even to a grandchild.

Is there an easy way to check this target element is part of a list item or do I need to walk the path from event.target till I reach a <li> element?

This is what I had before I decided to bind an event to the <ul> tag, which works but is not fast enough:

$('#list li').mousedown(function(){
    $(this).addClass('green');
});

And this is what I have now which doesn't work properly, mousedown on a child element doesn't give the <li> another classname:

$('#list').mousedown(function(event){
    if(event.target.nodeName == 'LI'){
        $(event.target).addClass('green');
    }
});

I wonder if my second way to achieve this is faster if there is not a simple solution to check if that target element is part of a list item...

+1  A: 

You need to check if there is a LI tag in the parents of the target element.

All of the common frameworks have a way of determining this, it is up() in prototype, ancestor() in YUI3, and looking at the JQuery docs, it seems like it has a parent(), and parents() function that you can use for this.

See: http://docs.jquery.com/Traversing

Haven't used JQuery, but it I assume checking for $(event.target).parent('li') is the answer.

WishCow
Actually you'd probably want ".closest('li')", but again with jQuery the whole problem is already solved by the framework.
Pointy
Hmm you are right. Misleading function names imo.
WishCow
+1  A: 

Well, you could do all of this with the jQuery "live" tool:

$('#list li').live('mousedown', function() {
  $(this).addClass('green');
});

You can read about what "live" does here: http://api.jquery.com/live/

Pointy
This is the same as `.mousedown()` except that it accepts newly created elements as well, am I right? If so, it won't help me, still I need to unbind 1000 events instead of 1.
Harmen
No, it is not the same as ".mousedown()." Check the documentation - the new "live()' API is doing exactly what you want.
Pointy
Oh and note that the built-into-jquery "live()" API is not the same as the older plugin with a similar name. That one would indeed bind event handlers directly to the elements. The new one takes advantage of bubbling, which is what (I think) you're asking for.
Pointy
Thank you; I hadn't noticed `.live()` was updated. Anyway, your piece of code still required thousand events. This helped me out eventually: `$('li', $('#list')).live('click', function(e){ ..});`. This requires one event and uses Event Context. If you update your comment I'll accept yours ;)
Harmen
Huh? 1000 events? No, it doesn't require 1000 events. Again, that is **not** how the new "live()" API works. Yes, the selector references all the "li" elements, but only one event handler is bound, and it's bound to the "body" element.
Pointy
Ok, +1, sorry Sir. I'll try to understand how it works and then I'll accept your answer.
Harmen
Now I get it, thank you! I tested it but .die() didn't work -- then I upgraded jQuery to 1.4.2 and it worked. Thank you very much!
Harmen
I'm very glad that it's working for you!! jQuery is a really nice library to work with. The API documentation is steadily getting better, too.
Pointy