Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to select consecutive elements that match a filter

Given this example:

<img class="a" />
<img />
<img class="a" />
<img class="a" id="active" />
<img class="a" />
<img class="a" />
<img />
<img class="a" />

(I've just used img tags as an example, that's not what it is in my code)

Using jQuery, how would you select the img tags with class "a" that are adjacent to #active (the middle four, in this example)?

You could do it fairly easily by looping over all the following and preceding elements, stopping when the filter condition fails, but I was wondering if jQuery could it natively?

like image 487
nickf Avatar asked Sep 17 '08 02:09

nickf


2 Answers

Here's what I came up with in the end.

// here's our active element.
var $active = $('#active');

// here is the filter we'll be testing against.
var filter = "img.a";

// $all will be the final jQuery object with all the consecutively matched elements.
// start it out by populating it with the current object.
var $all = $active;

for ($curr = $active.prev(filter); $curr.length > 0; $curr = $curr.prev(filter)) {
    $all = $all.add($curr);
}
for ($curr = $td.next(filter); $curr.length > 0; $curr = $curr.next(filter)) {
    $all = $all.add($curr);
}

For a follow up question, I could see how this could easily be generalised by making it into a function which takes two arguments: an initial element, and a filter string - can anyone point me in the right direction to find out how to extend the jQuery object to add such a function?


Edit: I've since found that the each() function would do this rather well for some purposes. In my own case it doesn't work as cleanly, since I want a single jQuery object for all those elements, but here's how you could use each for a different purpose (hiding consecutive ".a" elements, in this example:)

$('#active')
    .nextAll()
    .each(hideConsecutive)
    .end()
    .prevAll()
    .each(hideConsecutive)
;
function hideConsecutive(index, element) {
    var $e = $(element);
    if (!$e.is(".a")) {
        return false;    // this stops the each function.
    } else {
        $e.hide('slow');
    }
}

--

Edit: I've put this together into a plugin now. Take a look at http://plugins.jquery.com/project/Adjacent if you're interested.

like image 171
nickf Avatar answered Oct 06 '22 08:10

nickf


I believe looping is your best bet. But you could try, each active, and then move before and after until the condition breaks, which if the set is large enough would be faster.

like image 38
Xenph Yan Avatar answered Oct 06 '22 10:10

Xenph Yan