Question

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.

Was it helpful?

Solution

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.

OTHER TIPS

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.

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;
  } 
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top