简体   繁体   中英

Get index of element among siblings ignoring sibling with specific child

I have a specific use case I can't seem to find an answer to. Given the DOM elements below:

<div class="wrapper">
   <div class="item"></div>
   <div class="item">
       <div class="foo"></div>
   </div>
   <div class="item">
       <div class="bar"></div>
   </div>
   <div class="item"></div>
   <div class="item selected"></div>
   <div class="item"></div>
</div>

I need to find the index of the .selected element in regard to it's siblings. But I need to ignore any siblings that have the .foo child element (it will only ever be the direct child).

So typically to find the index of .item .selected you could use $(".item.selected").index() which gives 4 , but since one item before it has a .foo child the correct answer is 3 .

I thought, the best way to go about it was to grab all the siblings before the selected element (since siblings after it wouldn't shift it's index) and then count how many have a .foo child, and subtract that number from the selected index, so 4-1=3 . I tried to do that like this:

var selectedIndex = $(".item.selected").index();
var fooCount = $(".item.selected").prevAll('.item > .foo').length;
var finalIndex = selectedIndex - fooCount;

The problem is, fooCount is coming up 0 instead of 3 .

You can simply use .filter() and remove the preceding elements that have a given child.

 const selected = $('.selected'); const foos = selected.prevAll().filter(function() { return !($(this).find('.foo').length); }); console.log(selected.index(), foos.length); 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <div class="wrapper"> <div class="item"></div> <div class="item"> <div class="foo"></div> </div> <div class="item"> <div class="bar"></div> </div> <div class="item"></div> <div class="item selected"></div> <div class="item"></div> </div> 

Use this selector ".item:not(:has(.foo))" and then loop to find the specific index.

 var index = $(".item:not(:has(.foo))") .toArray() .findIndex(function(item) { return $(item).hasClass('selected'); }); console.log(index); 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <div class="wrapper"> <div class="item"></div> <div class="item"> <div class="foo"></div> </div> <div class="item"> <div class="bar"></div> </div> <div class="item"></div> <div class="item selected"></div> <div class="item"></div> </div> 

You were close.

Change:

var fooCount = $(".item.selected").prevAll('.item > .foo').length;

… to:

var fooCount = $(".item.selected").prevAll('.item:has(.foo)').length;

Otherwise, you're looking for a sibling with class .foo , when you actually want a sibling that has a child with class .foo .

Snippet:

 var selectedIndex = $(".item.selected").index(); var fooCount = $(".item.selected").prevAll('.item:has(.foo)').length; var finalIndex = selectedIndex - fooCount; console.log(finalIndex); 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <div class="wrapper"> <div class="item"></div> <div class="item"> <div class="foo"></div> </div> <div class="item"> <div class="bar"></div> </div> <div class="item"></div> <div class="item selected"></div> <div class="item"></div> </div> 

You can combine:

:not() : selects all elements that do not match the given selector.

:has() : reduce the set of matched elements to those that have a descendant that matches the selector or DOM element.

:index(element) : where element is the DOM element or first element within the jQuery object to look for.

Hence, you can change your code:

var selectedIndex = $(".item.selected").index();

to:

var selectedIndex = $('.item:not(:has(.foo))').index($('.item.selected'));

 var selectedIndex = $('.item:not(:has(.foo))').index($('.item.selected')); console.log(selectedIndex ); 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <div class="wrapper"> <div class="item"></div> <div class="item"> <div class="foo"></div> </div> <div class="item"> <div class="bar"></div> </div> <div class="item"></div> <div class="item selected"></div> <div class="item"></div> </div> 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM