views:

2986

answers:

5

In my javascript experience, I found that is a very common task "searching the nearest ancestor of an element with some condition (tag name, class,...)". Can the parents() method of jquery do the job? The order of returned elements of parents() is predictable? Is top-to-bottom or bottom-to-top? For the moment I use this utility function:

function ancestor(elem, selector) {
  var $elem = $( elem ).parent();
  while( $elem.size() > 0 ) {
    if( $elem.is( selector ) ) 
    return $elem;
    else
       $elem = $elem.parent();
  }
  return null;
}

Can someone tell me if there is a clever way to do the job?

+8  A: 

yep - parents() traverses up the tree.

<div id="a">
    <div id="b">
        <p id="c">
            <a id="d"></a>
        </p>
    </div>
</div>

$('#d').parents("div:first"); will select div b.

nickf
A: 

good solution! JQuery documentation doesn't specify the order of returned element, so I never used parents(). But probably jquery runs a bottom-up search through DOM parentNode so this is the natural ordering.

Thanks!!

Pier Luigi
+10  A: 

Adding to @nickf's answer:

jQuery 1.3 simplifyed this task with closest.

Given a DOM:

<div id="a">
    <div id="b">
        <p id="c">
            <a id="d"></a>
        </p>
    </div>
</div>

You can do:

$('#d').closest("div"); // returns [ div#b ]

[Closest returns a] set of elements containing the closest parent element that matches the specified selector, the starting element included.

Borgar
+3  A: 

You should use closest, because parents won't give you the result you expect if you're working with multiple elements. For instance, let's say you have this:

    <div id="0">
     <div id="1">test with <b>nested</b> divs.</div>
     <div id="2">another div.</div>
     <div id="3">yet <b>another</b> div.</div>
    </div>

and you want to add a class to the divs that have a <b> element as their immediate child (ie, 1 and 3). If you use $('b').parents('div'), you get divs 0, 1 and 3. If you use $('b').parents('div:first'), you only get div 1. To get 1 and 3, but not 0, you have to use $('b').closest(elem).

LaC
+1  A: 

closest() starts at current element, if the parent you are looking for has the same tag as current (eg. both are divs), use parent().closest()

Ron