views:

111

answers:

3

I have a list within lists. When a user clicks on a list item (<li>), I want the nested <ul> to show up. Before I started adding the nested lists, I just had it where clicking a list item would run a function. Now, clicking any of the nested lists also runs that function. Which makes sense, since they're part of the list item.

Besides wrapping a <span> around the first part of the list item and running the function on that, is there a selector that will let me run something on the parent <li> but not any of its children, specifically not the child lists and list items?

HTML:

<ul class="buckets">        
    <li class="bucket">
        <img src="arrow_group_collapsed_true.png" class="arrow">
        <img src="blue_folder.png" class="folder">
        View all
    </li>

    <li class="bucket">
        <img src="arrow_group_collapsed_false.png" class="arrow">
        <img src="blue_folder.png" class="folder">
        Groups
        <ul style="display: block;">
            <li id="group_id_15036" class="group_bucket">
                <img src="arrow_group_collapsed_true.png" class="arrow">
                <img src="blue_folder.png" class="folder">
                Group 1
            </li>
            <li id="group_id_14910" class="group_bucket">
                <img src="arrow_group_collapsed_true.png" class="arrow">
                <img src="blue_folder.png" class="folder">
                Group 2
            </li>
        </ul>
    </li>
</ul>

Javascript (not much of it, I can show more if needed):

$( 'li.bucket' ).live( 'click',
    function()
    {
        // do stuff
    })

I want a click on "Groups" or "View All" to run the click function, but a click on "Group 1" or "Group 2" should not.

+1  A: 

There's an official way, but in your case, it might be rather expensive:

$('li.bucket *').live('click', function(event) { event.stopPropagation() });

The li's children will now have a handler that stops the event from propagating upwards and triggering the li's handler. Please try it and see if the application isn't slowed down too much.

MvanGeest
So if a user clicks on anything like `li.bucket li`, what would happen here?
hookedonwinter
Nothing. Isn't that the intended behaviour?
MvanGeest
Ya, I just wanted to make sure. Can I then override that? I do want things to happen when I click the deeper links, I just don't want the function to fire on the top one as well. If that makes sense.
hookedonwinter
Essentially, I want the click function to run on all li's, but I want it to run on the li actually clicked, not a parent li.
hookedonwinter
Yes, you can override (well, actually, complement) that and it will work. The only thing that this code accomplishes is that none of the parents' `click` handlers will be triggered. Sounds like it's just what you want.
MvanGeest
Perfecto! thanks MvanGeest!
hookedonwinter
+1  A: 

you can control the above function onmouseover the list item & remove it onmouseout event of the item. But I don't know about how efficient it would be against other ways though.

loxxy
Cool idea. MvanGeest's worked, but good thinking :)
hookedonwinter
Hehe actually these ideas come when I'm too lazy to write a jQuery code...pretty easy to help people by just giving them the idea than code :p
loxxy
A: 

I like @MvanGeest's solution but there is a better way by understanding the event propagation. When an element is clicked the contained elements get the event first and trickle up through the tree. If I understand your request you would like to prevent the contained ul sending events up the tree. I think here a visual is best.

<ul>
  <li></li>
  <li onclick="ShowChildUL()">
    <ul onclick="function(event) { event.stopPropagation() }">
      <li onclick="DoSomethingFun()"></li>
      <li></li>
      </ul>
  </li>
</ul>

In this case you will see that the onclick on the ul in the middle will stop propagation up to the li. Also event.stopPropagation() is not cross browser. I recommend this method as your onclick function.

function StopPropagation(e) {
  var event = e || window.event;

  [body of event handler function goes here]

  if (event.stopPropagation) {
    event.stopPropagation();
  } else {
    event.cancelBubble = true;
  } 
}
Jonathan Park