rmurphey Adventures in JavaScript

Cycle through list elements with jQuery

8 Jan 2008 edit

I've written several versions of this functionality, and each time I revisit it, it gets simpler and I feel silly for how complicated I made it before. The thing to remember when you're working with jQuery is to always leverage the DOM. Christian Montoya has a good writeup about how he came to the same realization, and it's worth a read.

In the meantime, here's my latest iteration of cycling through items in an unordered list. In the example below, I've just put straight-up text in the list items, but they could contain entire divs of content if you wanted.

First, let's assume we have this HTML:

{% codeblock lang:html %}

  • Item 1
  • Item 2
  • Item 3
{% endcodeblock %} We'll start by verifying that there's more than one item before we do all the rest of the work. (Of course, if your list length doesn't vary, this if isn't necessary.) {% codeblock lang:javascript %} var $list = $('#myList'); if ($list.length > 1) { ... } {% endcodeblock %} Following the principles of progressive enhancement, we don't want to include navigation elements in the HTML if they will only work with Javascript; rather, we want to add them with Javascript: {% codeblock lang:javascript %} var $list = $('#myList'); if ($list.length > 1) { // put the nav before the list $list.before(''); // style the nav as needed $('#nav').css({textAlign: 'right'}); $('#nav img').css({cursor: 'pointer'}); $('#nav img:first').attr('src','backButton.gif'); $('#nav img:last').attr('src','forwardButton.gif'); } {% endcodeblock %} The comes the fun part: adding the behaviors to the nav buttons. This is where it pays to keep in mind the power of the DOM; in past iterations of this, I've seriously overthought the logic. {% codeblock lang:javascript %} var $list = $('#myList'); if ($list.length > 1) { // put the nav before the list $list.before(''); // style the nav as needed $('#nav').css({textAlign: 'right'}); $('#nav img').css({cursor: 'pointer'}); // add the back button behavior $('#nav img:first'). attr('src','backButton.gif'). click(function() { $('li:visible',$list). hide(). prev('li'). show(); }); // add the forward button behavior $('#nav img:last'). attr('src','forwardButton.gif'). click(function() { $('li:visible',$list). hide(). next('li'). show(); }); } {% endcodeblock %} But what happens if there's not a next li when you click on the forward button, or a previous li when you click on the back button? {% codeblock lang:javascript %} var $list = $('#myList'); if ($list.length > 1) { // put the nav before the list $list.before(''); // style the nav as needed $('#nav').css({textAlign: 'right'}); $('#nav img').css({cursor: 'pointer'}); // add the back button behavior $('#nav img:first'). attr('src','backButton.gif'). click(function() { $('li:visible',$list). hide(). prev('li'). show(); // if there wasn't a previous li, // show the last li in the list if ($('li:visible',$list).length {% endcodeblock %} One last thing: we need to hide all the list items and then show the first one: {% codeblock lang:javascript %} var $list = $('#myList'); if ($list.length > 1) { // hide all the list items and show the first one $('li',$list).hide().eq(0).show(); // put the nav before the list $list.before(''); // style the nav as needed $('#nav').css({textAlign: 'right'}); $('#nav img').css({cursor: 'pointer'}); // add the back button behavior $('#nav img:first'). attr('src','backButton.gif'). click(function() { $('li:visible',$list). hide(). prev('li'). show(); // if there wasn't a previous li, // show the last li in the list if ($('li:visible',$list).length {% endcodeblock %} For extra fun:
  • Randomly reorder the list items before you add the rest of the code
  • Instead of show() and hide(), try fadeIn() and fadeOut()

Comments