jQuery :random filter

, ,

While working on a new JavaScript mockup I needed a way to obtain a random jQuery item. While I could use jQuery(“selector”).get(int) to get a random item, I wanted to have a cleaner way of doing that to keep my code clean.

jQuery ships with great support for extensibility. You can not only extend jQuery with custom functions but filters as well. That is when I thought of the custom “:random” filter, just as you have the standard “:first”, “:last” and “:nth” filters.

Is jQuery capable of returning a random item?

While trying to get the “:random” filter working I’ve stumbled upon a challenge which kept making it all done impossible. As far as my understanding of the jQuery framework goes, it first selects all items based on the selector and then fires the logic defined at the filter to determine whether the particular item should be included in the returned match or not.

As far as I can tell the filter logic is being fired for each match and is supposed to return false if the match should be skipped and true if it should be included in the result. The problematic part here is “fired for each match”: as we are supposed to return a random item we should have one random number and then return only the item of which index is equal to the random number. Because the filter logic is fired for every item you would get a different random number at every run which could result in three scenarios:

  1. it might actually work and you would get exactly one item
  2. the filter would return multiple items, eg. random number 0 for the first item and 2 for third.
  3. the filter would return an empty array: eg. random number 3 for the first item and 0 for the last

The higher the number of matches the smaller the chance for scenario a as the routine for generating random number would be called more often.

Eventually I came with the following solution:

jQuery.jQueryRandom = 0;
jQuery.extend(jQuery.expr[":"],
{
    random: function(a, i, m, r) {
        if (i == 0) {
            jQuery.jQueryRandom = Math.floor(Math.random() * r.length);
        };
        return i == jQuery.jQueryRandom;
    }
});

Each time jQuery calls the “:random” filter the logic is being fired. The i parameter holds the index of the match returned by the selector. If it’s the first element in the match the random number will be generated and stored in the jQueryRandom variable. The random number is being generated based on the total number of matches returned by the selector which can be read from the r parameter. The rest is easy: if the index of the current item is equal to the random number, the current item should be included in the results.

You can use the “:random” filter as follows:

<ul>
    <li>First</li>
    <li>Second</li>
    <li>Third</li>
</ul>
<script type="text/javascript">
    $().ready(function() {
        alert($("li:random").text());
    });
</script>

Enjoy!

Technorati Tags: ,

Possibly related posts

12 Responses to “jQuery :random filter”

  1. Alexandre de Oliveira Says:

    Explendid. Very simple and useful.

    Thanks

  2. Alexandre de Oliveira Says:

    It seems to not be working on any IE.

    r.length returns the element\'s text string length (246, for example), not the number of elements. On any other browser, it returns correctly.

  3. e11world Says:

    I'm wondering how you would use this script for the following:
    Have random quotes on a page (li list). You would have the list but jQuery positions/reorders them randomly for each time the page refreshes?
    Any ideas?

  4. Waldek Mastykarz Says:

    @e11world: to be honest I would create new code to do the job. Instead of retrieving the separate li items using the :random filter I would retrieve the whole list at once, and then do the shuffling.

  5. Waldek Mastykarz Says:

    @Alexandre de Oliveira: it took a while, but I've just tested it in IE8 and it works perfectly. Could you provide any more details about your scenario?

  6. David Millar Says:

    Thank you for the awesome snippet of code! I'm currently working on a for-fun project making a story engine similar to text adventure games, and have been looking for good ways to randomize and limit options, and this will work perfectly!

  7. keo Says:

    Hi, thanks for the snippet it works fine but I'm getting same error that Alexandre de Oliveira in IE(8)
    please, you can fixed it?
    thank you!

  8. Waldek Mastykarz Says:

    @keo: could you provide some more information on how you're using it (eg. what is your HTML and what is your selector)?

  9. journalweblogthing » Twitter Weekly Updates for 2010-03-28 Says:

    [...] much liking this little bit of jquery code for random selections. http://blog.mastykarz.nl/jquery-random-filter/ [...]

  10. Allain Lalonde Says:

    Great snippet.

    For some reason I had to change my query slightly from:

    $("#section1 .links a:random")

    To:
    $("#section1 .links").find("a:random").

    r.length was considerably higher than it should have been in the first case, but the second selector worked fine.

    Thoughts?

  11. Renee Says:

    Can you provide any additional insight regarding using this snippet to display list items (li) in a random order?

    Many thanks for your work!

  12. Waldek Mastykarz Says:

    @Renee: the script I showed you allows you to pick a random item, not shuffle list items in a random order. I think you would need a whole different script for your scenario. Have you already tried looking up the jQuery plugins gallery?

Leave a Reply

Security Code:

WP Theme & Icons by N.Design Studio
Entries RSS Comments RSS
Copyright © 2007 - 2010 Waldek Mastykarz

Creative Commons License