Reputation: 5232
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
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
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
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
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