Wednesday, June 27, 2012

.parent() vs. .parents() vs. .closest()


All three of these methods are concerned with navigating upwards through
the DOM, above the element(s) returned by the selector, and matching
certain parents or, beyond them, ancestors. But they differ from each other
in ways that make them each uniquely useful.

PARENT(SELECTOR)
This simply matches the one immediate parent of the element(s). It can take
a selector, which can be useful for matching the parent only in certain
situations. For example:
$('span#mySpan').parent().css('background',
'#f90');
$('p').parent('div.large').css('background',
'#f90');
The first line gives the parent of #mySpan. The second does the same for
parents of all <p> tags, provided that the parent is a div and has the class
large.
Tip: the ability to limit the reach of methods like the one in the second line is
a common feature of jQuery. The majority of DOM manipulation methods
allow you to specify a selector in this way, so it’s not unique to parent().
PARENTS(SELECTOR)

This acts in much the same way as parent(), except that it is not restricted
to just one level above the matched element(s). That is, it can return
multiple ancestors. So, for example:
$('li.nav').parents('li');
//for
each
LI
that
has
the
class
nav,
go
find
all
its
parents/ancestors
that
are
also
LIs
This says that for each <li> that has the class nav, return all its parents/
ancestors that are also <li>s. This could be useful in a multi-level
navigation tree, like the following:
<ul
id='nav'>
<li>Link
1
<ul>
<li>Sub
link
1.1</li>
<li>Sub
link
1.2</li>
<li>Sub
link
1.3</li>

</ul>
<li>Link
2
<ul>
<li>Sub
link
2.1
<li>Sub
link
2.2
</ul>
</li>
</ul>
Imagine we wanted to color every third-generation <li> in that tree orange.
Simple:
$('#nav
li').each(function()
{
if
($(this).parents('#nav
li').length
==
2)
$(this).css('color',
'#f90');
});
This translates like so: for every <li> found in #nav (hence our each()
loop), whether it’s a direct child or not, see how many <li> parents/
ancestors are above it within #nav. If the number is two, then this <li>
must be on level three, in which case color.
CLOSEST(SELECTOR)
This is a bit of a well-kept secret, but very useful. It works like parents(),
except that it returns only one parent/ancestor. In my experience, you’ll
normally want to check for the existence of one particular element in an
element’s ancestry, not a whole bunch of them, so I tend to use this more
than parents(). Say we wanted to know whether an element was a
descendant of another, however deep in the family tree:


if
($('#element1').closest('#element2').length
==
1)
alert("yes
-­‐
#element1
is
a
descendent
of
#element2!");
else
alert("No
-­‐
#element1
is
not
a
descendent
of
#element2");
Tip: you can simulate closest() by using parents() and limiting it to
one returned element.
$($('#element1').parents('#element2').get(0)).css('background',
'#f90');
One quirk about closest() is that traversal starts from the element(s)
matched by the selector, not from its parent. This means that if the selector
that passed inside closest() matches the element(s) it is running on, it
will return itself. For example:
$('div#div2').closest('div').css('background',
'#f90');
This will turn #div2 itself orange, because closest() is looking for a
<div>, and the nearest <div> to #div2 is itself.


<br />