posted on:November 10, 2010

jQuery step custom position selector

One of the things I am most impressed when we talk about the jQuery is the selector engine. Accessing the DOM elements using selectors in jQuery has become such an easy task, even more so when you mention the fact that (most of) the selectors use the same expressions as a CSS selectors. That is something that non-programming web designer can easily relate to.
This article is a coding exercise in creating a custom selector you may use as a guide to create your own selector.

Download jquery.step.js bundle | View working demo

What am I trying to achieve?

Basically, I needed to get every 3rd element in a collection of elements. (I wanted to apply custom styling to every third element). I was trying to write a simple script for that purpose but then I thought why don’t I make a custom selector out if it.
Building custom selectors in jQuery is not that difficult so if you want to have a go at it here is a great article on the subject.

So my goal was to select elements at a certain step but in another case I also needed to start from the nth element not the first one… So this selector I am presenting here is capable of selecting elements at a certain step but also you can make an “offset” and start with selection at any point in a collection of elements.

Here is the complete code:

jQuery.expr[':'].step = function(node,index,meta){
	var $index = index;
	var $meta = meta[3].toString().split(',');
	var $step = parseInt($meta[0]);	
	var $start = ($meta.length > 1) ? $meta[1] : 0;
	if ($start != 0) $start -= 1;
	return ( ( ($index-$start) / $step ) == Math.floor( ( ($index-$start) / $step ) ) && ( ($index-$start) >= 0 )  );	

Take it step by step

In order to use this selector you will have to, of course link to a jQuery library and and also link to the jquery.step.js found in a download bundle.

<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="jquery.step.js"></script>

Step selector is used the regular, jQuery way. This would be the syntax if you want to select every third element:

$('ul#one li:step(3)').css('clear','left');

As mentioned this selector can accept the selection starting point. So if you want to select every 3rd element starting from the 5th element on, you would write it like this:

$('ul#two li:step(3,5)').addClass('alt');

First parameter 3 indicates the step and second parameter 5 indicates the starting point for the selection. Note that the parameters must be separated with comma.

Some practical uses

Let’s say you have a gallery of thumbnails floated left and you want to clear the float on every 4th thumbnail. Or you want to assign a specific class name to every 10th list item in order to visually group it. Or you want to insert adds before every 5th news item in your list but not before the first one … etc 🙂

Important note

Here’s one flaw that I couldn’t solve myself… No matter what I tried I couldn’t make it to work properly when I used selectors that included class names. This is an kind of example I had trouble with:

$(' li:step(3)').css('clear','left');

It turned out that jQuery selection engine doesn’t perform any preselecting when using class names so, when creating custom selector, from indexing point of view, writing this:

$(' li:step(3)').css('clear','left');

is just as same as writing this:

$('ul li:step(3)').css('clear','left');

Filtering by class names is done later, after the custom selector is being used so that is what makes this kinda incomplete.
If you have an idea how to solve this, please share, your name will be posted here and we will all be grateful 🙂

Enjoyed the article?

Then don't miss our next one! Subscribe to our RSS feed or share it with your friends.

DeliciousStumbleUpon RedditSubscribe

Comments (6 Comments)

  1. Nejo
    November 10, 2010

    There already exists a similar selector in jQuery: when you want an offset, simply put an equation adding the offset number. I see the same functionality, but I envy your work, and also greatings your link to help any other developer to extend jQuery.
  2. cssglobe
    November 10, 2010

    Thanks for pointing that out Nejo. This is article is now nothing but an exercise in creating custom selectors.
  3. Diego Perini
    November 10, 2010

    Good explanation on how to extend jQuery selectors but as Nejo said much of the functionality is already achieved by standard CSS syntax and jQuery extra selectors mostly duplicates the already rich CSS functionality. If you are interested in a better way to execute "custom functions" bound to structural/positional pseudo-classes I also suggest you have a look at NWMatcher decorator callback, this is the syntax you would use: selector, context, callback ); It ensures the passed "callback" will be invoked for each element matching the selection and will probably yield better performances. The "callback" function is passed the element reference as the only parameter, so this avoids having to loop twice over the same elements to apply changes on them.
  4. porcelanosa
    November 11, 2010

    About Impotant note: where is trouble? All woks correct.
  5. cssglobe
    November 11, 2010

    @porcelanosa: Actually it doesn't :( try changing IDs in example to class names and select them with this selector. You will see that it doesn't work properly. The :step() does the selecting before the ULs are filtered by class names so the indexing is wrong. In this case indexing is important so If you want to get a clearer picture of what happens here just insert this line of code just before the last line (where the script returns the node) so you can see each element's index: $(node).html(index); You will notice that the first element in second UL doesn't have zero index but it continues as if it was part of the same element collection.
  6. Walter Apai
    November 11, 2010

    Excellent Article given by you, thanks a lot. Keep posting more.

Sorry, the comment form is closed at this time.