views:

682

answers:

3

i am actually doing a accordion/sliding menu. here, i want to slide up sibling li > ul that has been open (or displayed). can i simplify this further?

$(this).parent("li").siblings("li:has(ul)").children("ul").slideUp("fast");

i also noticed that i cannot skip the children() part and do something like

$(this).parent("li").siblings("li:has(ul) ul").slideUp("fast");

why is siblings("li:has(ul) ul") different from siblings("li:has(ul)").children("ul")?

A: 

This is due to the nature of the siblings selector. Think of it this way: it takes $('li:has(ul) ul') and $(this).parent("li").siblings() and returns a jQuery object populated with the intersection of the two. In other words, it's looking for unordered lists that are children of list items that have UL children that are siblings of $(this).parent.

cpharmston
+1  A: 

Finds all the direct children of <li>s that have <ul> inside:

$("li:has(ul)").children("ul")

//or
$("li:has(ul) > ul")

Finds all the descendants of <li>s that have <ul> inside:

$("li:has(ul) ul")
Keith
The question was about why the siblings method works differently, no about how to do the selection. In both cases it selects the unordered lists inside the list elements, though the latter would also select unordered lists at any depth, not just the immediate children.
tvanfosson
Actually the question is: why is siblings("li:has(ul) ul") different from siblings("li:has(ul)").children("ul")? The siblings operator provides the context, but my point is that the "li ul" returns all ul *descendants" while .children returns direct children (like "li > ul"). It's a really common confusion as .parents returns all ancestors.
Keith
+2  A: 

In the first case you are selecting the list elements that are siblings as long as those list elements have unordered lists as children, then you get the unordered list children. In the second case you are looking for siblings that are unordered lists that are children (immediate or nested) of list elements. The problem is that you are looking in the siblings of a list element which has no unordered list siblings (only list element siblings).

The key is that the selector in the siblings method is a filter. It is only used to select out of the list of unique siblings, those siblings that match the criteria specified in the selector. In your case, there aren't any siblings that do (can) match the criteria in the second case.

Example:

<ul>
     <li id='li0' class='selected'>
         <ul id='ul0' class='child'>
            ...
         </ul>
     </li>
     <li id='li1' class='sibling'>
        <ul id='ul1' class='child'>
           ...
        </ul>
     </li>
     <li id='li2' class='sibling'>
        <ul id='ul2' class='child'>
           <li id='li2_0' class='grandchild'>
              <ul id='ul2_0' class='greatgrandchild'>
                 ...
              </ul>
           </li>
        </ul>
    </li>
    <li id='li3'>
    </li>
</ul>

$('.selected').siblings('li:has(ul)') will return the collection of list elements with ids li1 and li2. $('.selected').siblings('li:has(ul) ul') will return an empty set because it is the same as $('.selected').siblings().filter('li:has(ul) ul'). Since siblings returns the set with ids li1' and li2`, these don't match the filter which selects the unordered list children of a list element (with unordered list children).

You can see the effect using the following snippet of code.

$(function() {
    dumpIds('siblings',$('.selected').siblings());
    dumpIds('filtered sibs',$('.selected').siblings('li:has(ul)'));
    dumpIds('ul filtered sibs',$('.selected').siblings('li:has(ul) ul'));
});

function dumpIds(title,elements) {
    var idset = '';
    var sep = '';
    elements.each( function() {
     idset = idset + sep + this.id;
     sep = ', ';
    });
    alert(title + ':' + idset);
}
tvanfosson
wow i am still confused at this 1 ... i may need more help/time understanding this... "The problem is that you are looking in the siblings of a list element which has no unordered list siblings (only list element siblings)." ... why "no unordered list siblings" i thought "li:has(ul) ul" will get li's that have ul and get those ul's
iceangel89
Yes, but only if they are in the set of siblings of the list element -- which they are not. They are children of the list element's siblings.
tvanfosson
oh i kind of get it now.
iceangel89