views:

24

answers:

3

JQUERY:

<script type="text/javascript">
 $(document).ready(function() {
  $('li.directory > ul').css('display','none');
  $('li.directory').click(function () {
   $(this).toggleClass('expanded');
   $('ul', this).slideToggle('slow');
  });

 });
</script> 

HTML: markup fixed now for demo

<ul>
  <li class="directory"><a href="#">Parent Link</a>
    <ul>
      <li><a href="#">Sibling Link</a></li>
      <li><a href="#">Sibling Link</a></li>
      <li><a href="#">Sibling Link</a></li>
    </ul>
  </li>
  <li class="directory"><a href="#">Parent 2 Link</a>
    <ul>
      <li><a href="#">Sibling Link</a></li>
      <li><a href="#">Sibling Link</a></li>
      <li><a href="#">Sibling Link</a></li>
    </ul>
  </li>
</ul>

This reads to me: When the document is ready, hide any UL with a parent LI of class "directory". If an LI with class "directory" is clicked, add the "expanded" class (display:block), and slideToggle the child UL in to view.

If the LI.directory is clicked again, hide the child UL again.

This works fine. For some reason, this slide behaviour is applied when I click the sibliing LIs. My JQUERY (I believe) is selecting only LIs with a class of directory? So why should class-less LIs be affected.

I'm creating like an interactive document tree and it works fine except for the child LIs firing the SlideToggle event.

Any ideas?

Thanks!

+1  A: 

There's quite a few things that are wrong, or weird about the code you gave. First, the HTML is invalid. To create second level lists, like

  • Level One
    • Level Two

Your ul list should be inside a li. In fact, nothing should be found inside ol and ul lists except li list items. Similarly, the li should also not appear anywhere except in lists. The fact that the HTML is invalid is reason enough for the effects to go haywire.


Additionally, lines like

$('li.directory > ul').css('display','none');

Can be written better as

$('li.directory > ul').hide();

Try not to use context, like $('ul', this), if only because $(this).children('ul') is more readable.


Edit Well in that case, the @jensgram's comment is corrent - because the links inside the li.directory are children, clicking on them also means clicking on their parents. So what you need to do is to limit your event handler to the anchor inside each li.directory, like so:

$('li.directory > a').click(function(event) {
    var current = $(this);

    current.parent().toggleClass('expanded');
    current.next().slideToggle('slow');

    return false;
});

Notice I've also changed some of the DOM travesal code to work with the new selector. See it live here: http://www.jsfiddle.net/Yq8U3/

Yi Jiang
whoops, my html markup is fine on my live code, rewrote it in a hurry for the demo. have fixed it now in my original post.thanks for the tip about .hide() having correct html markup, is there any explanation for said behaviour?thanks again
Ross
thanks again for the explanation and clarification
Ross
+2  A: 

None of your ul's have parents with a class of .directory <- They're being closed before the ul starts.

Try this:

<ul>
  <li class="directory">
     <a href="#">Parent Link</a>
     <ul>
        <li><a href="#">Sibling Link</a></li>
        <li><a href="#">Sibling Link</a></li>
        <li><a href="#">Sibling Link</a></li>
     </ul>
   </li>
</ul>

A working example: http://jsfiddle.net/GdCrr/

Sam
thanks, sorry my markup was fine on my live code, had rewritten demo in a hurry.my current version works exactly as the link you provided. I would like to prevent the slide toggle on the "sibling" li's, so when the ULs slide in to view, they remain visible until the "li.directory" is clicked again.also +1 for that link, what a useful site.
Ross
+1  A: 

The core problem is that a click on a child <li> is still a click inside a parent <li>, and so the click event bubbles up, triggering the parent event handler. To prevent this you can use event.stopPropagation() on any level before it gets there, for example:

$("li.directory li").click(fuction(e) {
  e.stopPropagation();
});

Or, re-written a bit to place it on the child <ul> you're already dealing with:

$(function() {
  $('li.directory').click(function () {
    $(this).toggleClass('expanded').children('ul').slideToggle('slow');
  }).children('ul').hide().click(function(e) {
    e.stopPropagation();
  });
});​

You can give it a try here

Nick Craver
works a treat, thanks a lot. +1 for the bubbles up link and vastly improved jquery code.
Ross