henry
henry

Reputation: 119

Selecting an element with the closest common ancestor

I need to find a way to select a DOM element that shares the closest common ancestor with a given element.

Here's what I mean:

<div class="grandparent">
   <span class="match not-this-one">
   <div class="parent">
      <span class="match this-one">
      <div class="container">
         <span class="me">
      </div>
</div>

I want something that does this:

$('.me').closestCousin('match'); selects <span class="match this-one">

closest() and parent() select ancestors, but don't look for cousin elements.

Upvotes: 0

Views: 469

Answers (4)

simohe
simohe

Reputation: 651

$('.me').closest(':has(.match)').find('.match')

Selects the closest common ancestor (the closest element containing a descendant with matching class). And then selects the matching descendant(s). The search is for any descentants, not children only!

  • e1
    • .match two
    • e2
      • e3
        • .match one
    • e2b
      • .me

.match one would be found here.

to get .match two in above case, run:

$('.me').parents().children('.match').first()

select all ancestors (closest listed first), then get their children matching the criteria. Take the 1st one since this is the closest one.

Upvotes: 0

Dave
Dave

Reputation: 10924

I think your best bet is to write a recursive function that combines the use of .prev() and .parent() to find your closest cousin.

Edit: I misunderstood the question. This solution searches up the tree to find the closest target, and as a byproduct of its implementation will also find siblings to the original element.

function closestCousin(me, target) {
  var cousin = me.prev(target);
  if (cousin.length) {
    return cousin;
  } else {
    var parent = me.parent();
    if (parent.length) {
      return closestCousin(parent, target);
    } else {
      return parent;  
    }
  }
}

var me = $(".me");
closestCousin(me, ".match").css("color", "red");
closestCousin(me, ".match2").css("color", "blue");
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="grandparent">
   <span class="match match2 not-this-one">Don't Match</span>
   <div class="parent">
      <span class="match this-one">Match</span>
      <div class="container">
         <span class="me">Me</span>
      </div>
   </div>
</div>

Upvotes: 1

guest271314
guest271314

Reputation: 1

You can use .closest() with selector :not(.me) to exclude current element from being matched by .closest(); siblings() with selector .match

$(".me").closest(":not(.me)").siblings(".match").addClass("matched")
.matched {
  color:blue;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">
</script>
<div class="grandparent">
   <span class="match not-this-one">not-this-one</span>
   <div class="parent">
      <span class="match this-one">match this-one</span>
      <div class="container">
         <span class="me">me</span>
      </div>
</div>

Upvotes: 1

Gerard
Gerard

Reputation: 15786

This should work: $('.me').closest('.match');

But it only goes up the DOM tree. If that's what you need,

Upvotes: 0

Related Questions