jQuery to find all previous elements that match an expression

javascript, jquery

Solution

Ok, here's what I've come up with - hopefully it'll be useful in many different situations. It's 2 extensions to jQuery that I call `prevALL` and `nextALL`. While the standard `prevAll()` matches previous siblings, `prevALL()` matches ALL previous elements all the way up the DOM tree, similarly for `nextAll()` and `nextALL()`.

I'll try to explain it in the comments below:

// this is a small helper extension i stole from
// http://www.texotela.co.uk/code/jquery/reverse/
// it merely reverses the order of a jQuery set.
$.fn.reverse = function() {
    return this.pushStack(this.get().reverse(), arguments);
};

// create two new functions: prevALL and nextALL. they're very similar, hence this style.
$.each( ['prev', 'next'], function(unusedIndex, name) {
    $.fn[ name + 'ALL' ] = function(matchExpr) {
        // get all the elements in the body, including the body.
        var $all = $('body').find('*').andSelf();

        // slice the $all object according to which way we're looking
        $all = (name == 'prev')
             ? $all.slice(0, $all.index(this)).reverse()
             : $all.slice($all.index(this) + 1)
        ;
        // filter the matches if specified
        if (matchExpr) $all = $all.filter(matchExpr);
        return $all;
    };
});

usage:

$('.myLinks').click(function() {
    $(this)
        .prevALL('.findme:first')
        .html("You found me!")
    ;

    // set previous nodes to blue
    $(this).prevALL().css('backgroundColor', 'blue');

    // set following nodes to red
    $(this).nextALL().css('backgroundColor', 'red');
});

edit - function rewritten from scratch. I just thought of a much quicker and simpler way to do it. Take a look at the edit history to see my first iteration.

edit again - found an easier way to do it!

Problem

Using jQuery, how do you match elements that are prior to the current element in the DOM tree? Using `prevAll()` only matches previous siblings. eg: ``` <table> <tr> <td class="findme">find this one</td> </tr> <tr> <td><a href="#" class="myLinks">find the previous .findme</a></td> </tr> <tr> <td class="findme">don't find this one</td> </tr> </table> ``` In my specific case, I'll be searching for the first `.findme` element prior to the link clicked.

Original source