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.

hookedonwinter
  • 12,436
  • 19
  • 61
  • 74

3 Answers3

11

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
  • 9,536
  • 4
  • 41
  • 41
  • So if a user clicks on anything like `li.bucket li`, what would happen here? – hookedonwinter Jul 27 '10 at 17:48
  • Nothing. Isn't that the intended behaviour? – MvanGeest Jul 27 '10 at 17:49
  • 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 Jul 27 '10 at 17:50
  • 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 Jul 27 '10 at 17:51
  • 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 Jul 27 '10 at 17:51
2

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
  • 12,990
  • 2
  • 25
  • 56
  • 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 Jul 27 '10 at 18:16
1

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
  • 775
  • 5
  • 12