jQuery find closest previous sibling with class

126,174

Solution 1

Try:

$('li.current_sub').prevAll("li.par_cat:first");

Tested it with your markup:

$('li.current_sub').prevAll("li.par_cat:first").text("woohoo");
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul>
  <li class="par_cat"></li>
  <li class="sub_cat"></li>
  <li class="sub_cat"></li>
  <li class="par_cat">// this is the single element I need to select</li>
  <li class="sub_cat"></li>
  <li class="sub_cat"></li>
  <li class="sub_cat current_sub">// this is where I need to start searching</li>
  <li class="par_cat"></li>
  <li class="sub_cat"></li>
  <li class="par_cat"></li>
</ul>

will fill up the closest previous li.par_cat with "woohoo".

Solution 2

Try

$('li.current_sub').prev('.par_cat').[do stuff];

Solution 3

Using prevUntil() will allow us to get a distant sibling without having to get all. I had a particularly long set that was too CPU intensive using prevAll().

var category = $('li.current_sub').prev('li.par_cat');
if (category.length == 0){
  category = $('li.current_sub').prevUntil('li.par_cat').last().prev();
}
category.show();

This gets the first preceding sibling if it matches, otherwise it gets the sibling preceding the one that matches, so we just back up one more with prev() to get the desired element.

Solution 4

I think all the answers are lacking something. I prefer using something like this

$('li.current_sub').prevUntil("li.par_cat").prev();

Saves you not adding :first inside the selector and is easier to read and understand. prevUntil() method has a better performance as well rather than using prevAll()

Share:
126,174

Related videos on Youtube

daulex
Author by

daulex

Updated on April 03, 2021

Comments

  • daulex
    daulex about 3 years

    Here's the rough HTML I get to work with:

    <li class="par_cat"></li>
    <li class="sub_cat"></li>
    <li class="sub_cat"></li>
    <li class="par_cat"></li> // this is the single element I need to select
    <li class="sub_cat"></li>
    <li class="sub_cat"></li>
    <li class="sub_cat current_sub"></li> // this is where I need to start searching
    <li class="par_cat"></li>
    <li class="sub_cat"></li>
    <li class="par_cat"></li>
    

    I need to traverse from the .current_sub, find the closest previous .par_cat and do stuff to it.

    .find("li.par_cat") returns the whole load of .par_cat (I've got about 30 on the page). I need target the single one.

  • daulex
    daulex about 14 years
    thank you Karim. This worked well too, but I assume the .prev() would eat less resources, as .prevAll would get ALL the previous matched elements and then would filter the one I need. Accepting Ed's answer.
  • daulex
    daulex about 14 years
    Actually, after a bit of texting, the .prev() failed in a few instances. .prevAll with :first, worked every time. Thank you.
  • David Hobs
    David Hobs almost 12 years
    Wait, what? Doesn't this only check the immediately preceding element? Thus your code would return null? - Here it is tested on jsFiddle: jsfiddle.net/Y2TEH
  • David Hobs
    David Hobs almost 12 years
    .prev() only checks the immediately preceding element. I added the comment to the answer below along with the jsFiddle exemplifying. After looking around, this is the best answer as although it has to cycle through all the elements, it doesn't require two functions to grab all then filter to find it.
  • Ed James
    Ed James almost 12 years
    @DavidHobs I wrote this two years ago.... I certainly would use prevAll() these days.
  • NReilingh
    NReilingh about 11 years
    Does this mean :first is working on a list of returned elements that starts closest to the selected object (as opposed to top to bottom relative to the page)?
  • Johansrk
    Johansrk about 10 years
    yeah the :first is needed, otherwise all prev will be selected. Thanks a lot for this answer
  • Hugo Zink
    Hugo Zink over 8 years
    @EdWoodcock consider updating your answer, in that case.
  • Accountant م
    Accountant م almost 7 years
    Thank you very much for the very useful answer. Can you please answer @NReilingh question because it's really confuses me. Isn't :first a CSS selector that selects the first element in DOM (e.g div.red:first will select the first red DIV in the DOM) did jQuery parse the selector differently ?
  • JasonWilson
    JasonWilson over 3 years
    I tried this one first, what happened is prevUntil returns many elements, then it gets prev() for each of the many elements. The desired result is one element
  • TylerH
    TylerH over 3 years
    @Accountantم There is no CSS selector called :first.
  • Accountant م
    Accountant م over 3 years
    @TylerH oh now that makes sense, thanks. It's a jQuery only selector and it's free to parse it as it likes :D.