Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

jQuery selector: all but n first in a row

So I have a list of siblings like so;

  <div class="b"></div>
<div class="a"></div>
  <div class="b"></div>
  <div class="b"></div>
  <div class="b"></div>
  <div class="b"></div>
<div class="a"></div>
  <div class="b"></div>
  <div class="b"></div>
<div class="a"></div>
<div class="c"></div>
  <div class="b"></div>
  <div class="b"></div>
  <div class="b"></div>
  <div class="b"></div>
  <div class="b"></div>
  <div class="b"></div>
  <div class="b"></div>

(Note: The b's are not children of the a's, they're all siblings. Indentation is for emphasis.)

In jQuery, I need to select each b, forgoing the first n elements in a streak. There is no specific type/class of element that breaks the streak, nor any dependable number of b's in a streak, or non-b elements in between.

If I used the selector to add a class selected, and supposing n = 2, my DOM would then look like so;

  <div class="b"></div>
<div class="a"></div>
  <div class="b"></div>
  <div class="b"></div>
  <div class="b selected"></div>
  <div class="b selected"></div>
<div class="a"></div>
  <div class="b"></div>
  <div class="b"></div>
<div class="a"></div>
<div class="c"></div>
  <div class="b"></div>
  <div class="b"></div>
  <div class="b selected"></div>
  <div class="b selected"></div>
  <div class="b selected"></div>
  <div class="b selected"></div>
  <div class="b selected"></div>

In other words, select every b except for n elements after anything else than b, or the beginning.

I've tried :nth-child(n+3), but that simply seems to take all the b's into account, despite the a's that break them.

I also tried fiddling around with .nextUntil() and .filter(), but it must take a better man than me to crack this. Ideas?

like image 520
Emphram Stavanger Avatar asked Feb 03 '13 14:02

Emphram Stavanger


1 Answers

Since these elements are all siblings that share the same parent, some clever use of sibling combinators will do the trick:

$('.b + .b + .b').addClass('selected');

For any n, simply repeat .b + n times before the last .b.

No need for :nth-child() or any traversing/filtering functions, and is also a valid and well-supported CSS selector, in case you're looking to apply styles to these elements.

jsFiddle preview


If you need to add an intermediate element before each set of .b + .b + .b elements, add the class first, then prepend the intermediate element before the first of each set of those matched elements. The first of these elements can be matched by looking behind it for an element that isn't .selected, which excludes everything that does have a .selected directly behind it:

$('.b + .b + .b').addClass('selected')
                 .filter(':not(.selected) + .selected')
                 .before('<div class="inserted"></div>');

Updated jsFiddle preview

If chaining too many methods gets confusing, you can always do each step separately:

$('.b + .b + .b').addClass('selected');
$(':not(.selected) + .selected').before('<div class="inserted"></div>');
like image 63
BoltClock Avatar answered Sep 21 '22 10:09

BoltClock