Raphael Jeger
Raphael Jeger

Reputation: 5232

Find closest sibling using jQuery

Given the following DOM

<ul>
     <li data-id="1">
     <li data-id="2">
     <li data-id="3">
     <li data-id="1">
</ul>

We need to find the closest <li>-Element with data-id="1" to the one with data-id="3"

We tried:

$('[data-id=3]').siblings('[data-id=1]').first()

which of course returns the first in DOM and not the closest

We also tried:

$('[data-id=3]').closest('[data-id=1]')

which does not work as it's only returning ancestors.

Thanks for any hints.

Upvotes: 6

Views: 4361

Answers (4)

KAD
KAD

Reputation: 11112

Obtain the closest by looping through the siblings and finding the minimum index relative to the current element index i.e $('[data-id=3]') :

var mainIndex = $('[data-id=3]').index('li');
    var minDif = 999;
    var closestIndex = 0;

    $('[data-id=3]').siblings('[data-id=1]').each(function(index)

      if(Math.abs($(this).index('li') - mainIndex) < minDif)
      {
        minDif = Math.abs($(this).index('li') - mainIndex);
        closestIndex = $(this).index('li');
      }

    });


    $('[data-id]').eq(closestIndex);

Upvotes: 0

Jamiec
Jamiec

Reputation: 136104

A nice simple jQuery plugin for your needs is one way to go:

(function ( $ ) {

    $.fn.closestSiblingByIndex = function(selector) {
        var thisIndex = this.index();
        var siblings = this.siblings(selector).map(function(i,e){
            return {
                element: $(this),
                diff: Math.abs($(this).index() - thisIndex)
            }
        }).get().sort(function(a,b){return a.diff-b.diff;});
        if(siblings.length == 0){
            return $();
        }
        else{
            return siblings[0].element
        }
    };

}( jQuery ));

Then the usage would be, for example:

$("li[data-id='3']").closestSiblingByIndex("li[data-id='1']");
                    .css('background-color','red')

of course, in this example changing that to:

$("li[data-id='2']").closestSiblingByIndex("li[data-id='1']");
                    .css('background-color','green')

will highlight the other li.

Live example: http://jsfiddle.net/u4b8w9dg/1/

Upvotes: 0

AmmarCSE
AmmarCSE

Reputation: 30557

Using nextUntil() and prevUntil() you can calculate which direction has the closest sibling and then determine whether to use next() or prev()

var nextLength = $('[data-id="3"]').nextUntil('[data-id="1"]').length;
var prevLength = $('[data-id="3"]').prevUntil('[data-id="1"]').length;
var closestSibling;
if (nextLength > prevLength) {
  closestSibling = $('[data-id="3"]').prev('[data-id="1"]');
} else {
  closestSibling = $('[data-id="3"]').next('[data-id="1"]');
}
console.log(closestSibling.text());
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<ul>
  <li data-id="1">second closest</li>
  <li data-id="2"></li>
  <li data-id="3"></li>
  <li data-id="1">first closest</li>
</ul>

Upvotes: 4

Rory McCrossan
Rory McCrossan

Reputation: 337560

To retrieve the data-id="1" element nearest to the currently selected based on their index, you can first sort the elements by the proximity of their index, then get the first. Try this:

var currentIndex = $('[data-id="3"]').index();
$('[data-id="1"]').sort(function (a, b) {
    var aDelta = Math.abs($(a).index() - currentIndex);
    var bDelta = Math.abs($(b).index() - currentIndex);
    return aDelta > bDelta;
}).first().addClass('foo');
.foo {
  color: #C00;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
    <li data-id="1">1</li>
    <li data-id="2">2</li>
    <li data-id="3">3</li>
    <li data-id="1">1</li>
</ul>

To test it works, change data-id="3" in the selector to data-id="2". You'll see the first li with data-id="1" gets the class applied to it.

Upvotes: 1

Related Questions