Find closest sibling using jQuery
Asked Answered
F

4

6

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.

Franck answered 3/7, 2015 at 8:29 Comment(7)
How are you defining 'closest' in this case? The element with the closest index to the current?Variform
You want before or after sibling?Feints
Do you actually mean next? not closest?Vaudevillian
I actually mean the closest element compared to the starting point, so, the last data-id=1 is closer if starting point is data-id=3, the first data-id=1 is closer if starting point is data-id=2Franck
@RoryMcCrossan yes, you are absolutely right!Franck
@RaphaelJeger I added an answer for youVariform
Does this answer your question? jQuery getting closest sibling element from $(this) not workingFragmentation
M
4

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>
Melloney answered 3/7, 2015 at 8:43 Comment(1)
thanks. Your solution is the most readable so we work with this.Franck
V
1

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.

Variform answered 3/7, 2015 at 8:41 Comment(0)
A
0

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);
Acquiesce answered 3/7, 2015 at 8:44 Comment(0)
A
0

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/

Asir answered 3/7, 2015 at 8:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.