Reversed Ordered List with jQuery

At work this past week, a client requested something that I wasn’t sure how to achieve: a reversed ordered list. So basically, they wanted to have a top 10 list, with the first item being numbered 10 and the last 1.

If you want to skip ahead to the demo, go ahead.

View Demo

Now sure, I could have just written the numbers in as text, but it’s a list, and it’s ordered! Here is an example of what the client wanted:

10. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
9. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
8. Lorem ipsum dolor sit amet, consectetur adipiscing elit.

1. Lorem ipsum dolor sit amet, consectetur adipiscing elit.

After some digging around, I found out that you can add the value attribute to each list item to specify the number to display. So basically, I just needed to code my list like this:

<ol>
 <
li value="10">Lorem ipsum dolor sit ametconsectetur adipiscing elit.</li>
 <
li value="9">Lorem ipsum dolor sit ametconsectetur adipiscing elit.</li>
 <
li value="8">Lorem ipsum dolor sit ametconsectetur adipiscing elit.</li>
 &
hellip;
 <
li value="1">Lorem ipsum dolor sit ametconsectetur adipiscing elit.</li>
</
ol

Pretty straightforward, but also pretty ugly. So what happens when the client decides they want to insert another bullet in the middle of the list? Yep, that’s right, they would have to adjust the numbering for the rest of the list.

Pretty crappy, so let’s use the powerfulness of jQuery to make this a little better.

The Markup

So just like before, we just want to create an ordered list, but this time, we will leave off the value attribute. We are also going to add a class to the ordered list that we will use as a hook to add in the jQuery functionality:

<ol class="reversed">
 <
li>Lorem ipsum dolor sit ametconsectetur adipiscing elit.</li>
 <
li>Lorem ipsum dolor sit ametconsectetur adipiscing elit.</li>
 <
li>Lorem ipsum dolor sit ametconsectetur adipiscing elit.</li>
 &
hellip;
 <
li>Lorem ipsum dolor sit ametconsectetur adipiscing elit.</li>
</
ol

The jQuery

Mapping out the code a bit: we want to select each element with a class of reversed, and count the total number of children list items. Then, we want to loop through the children, and update the value attribute to be the value of the total number of children minus a counter variable that we started at zero and increment each time through the loop.

That seems relatively straightforward, so I’ll just show the code that I wrote:

$(document).ready(function() {
 
$('.reversed').each(function() {
  
var $children = $(this).children('li');
  var 
totalChildren $children.length;
  var 
start 0;
  
$children.each(function() {
   
$(this).val(totalChildren start);
   
start++;
  
});
 
});
}); 

View Demo

It looks like with HTML 5, we get a reversed attribute that accomplishes the same thing, but until it’s fully supported, this quick & easy solution seems to work.

On a Personal Note

I have been severely neglecting my blog, but for good reason. I have been teaching some intro to web development courses at CDIABU in Georgetown. Also, I will be starting a new job on December 1st. I will be joining the amazing team at Viget Labs as their new front-end developer.

15 Comments

Tom

11.11.2009

Cool. Just in time for the end of year ‘best of’ lists to start up.

Nate

11.11.2009

Sometimes it’s the simple things in life. One of the things I love about jQuery is finding out how effortless and straightforward it is to do deeply satisfying things like this to one’s code.

The only, very small, concern I have about this is that the meaning of the ordered list in so far as the mark-up is concerned is exactly opposite what you intend it to be. The javascript doesn’t just enhance the presentation of the list, it flips the meaning. I’m not sure how terribly concerned I am about the browsers that view our sites without javascript, but violating the philosophical separation of meaning:markup / behavior:script bothers me a little bit.

Nate

11.11.2009

I’d suggest, as an alternative, actually reordering the items in the list as well as adding values, so that the meaning that’s in the mark-up—that list of 1-10 items—is accurate, but simply presented in a different order than you’ll accomplish via javascript.

Nate

11.11.2009

This is the sort of thing I mean:

This is number one.
 
This is number two.
 
This is number three.
 
This is number four
$(document).ready(function() {
 
$('.reversed').each(function() {
  
var children = $(this).children('li').get();
  $(
this).empty();
  
children.reverse();
  
  $(
this).append(children);
  
  $(
children).each(function() {
   
$(this).val(children.length - $(children).index(this));
  
});
  
 
});
}); 

Nate

11.11.2009

Hmm—that code didn’t exactly format the way I would’ve liked. Help a brother out?

Trevor

11.11.2009

@Nate-
<pre> tag sir…

I guess reordering the list does add some sort of semantic value, but how much really? It depends if there is any value given to item 10 vs. item 1.

Nate

11.11.2009

I had <pre> tags, man: I think it was stripped out by your demon CMS. (Don’t be sad, WordPress, I didn’t mean it.)

I guess technically there’s nothing but order necessarily implied by an unordered list, but there are default ways, as far as browsers are concerned, of interpreting them, and the default is as a numbered list. In this instance, I think browsers behave just like any reader would: unless we’re explicitly told otherwise, the numbers start at one and proceed upwards.

Nate

11.11.2009

@Nate-
Of course, by “unordered” above, I mean “ordered”.

Trevor

11.11.2009

@Nate-
Stupid WordPress.

Agreed, so I guess it just depends on whether there is a reference somewhere on the page saying that this list is presented in a certain order for a specific reason. If not, then I don’t think too much value is added in reversing it for non-JavaScript users.

I wonder what kind of load reversing the list adds to the page. I’m sure it’s trivial in this example since the list is so short, but what about a list with 100 items?

Nate

11.11.2009

@Trevor-

I think if you say, “This is our list of $whatevers”, and you have an ordered list of items, the meaning of those items is the same as if they had an invisible #1-10 next to them. Whether that ranking means “best” or “worst” or “funniest” or whatever is, of course, subject to the nature of the content. But it makes me feel like it’s still well worth having the script reverse the actual items.

That said, there’s no denying there’s a performance difference between just setting the value and rearranging the elements. I profiled the four-item ordered list and then a 120-item ordered list with each of our scripts, with these results:

Your script:

4: 1.37ms
120: 21.164ms

My script:

4: 3.608ms
120: 63.695ms

Trevor

11.11.2009

@Nate-
Wow, thanks for running the performance tests. Your point about reversing the list items is certainly valid and a nice addition to the example.

Judd Lyon

11.13.2009

Nice little trick, thanks!

Congrats on teaching and the new gig with Viget, they are an impressive outfit that just got better.

Cheers.

Trevor

11.14.2009

@Judd Lyon-
Thanks, I’m excited!

Steward

11.23.2009

May be better without unnecessary variable “start”?

$(document).ready(function() {
 
$('.reversed').each(function() {
  
var $children = $(this).children('li');
  var 
totalChildren $children.length;
  
$children.each(function() {
   
$(this).val(totalChildren--);
  
});
 
});
}); 

I don’t understand - what what do you use “var start = 0;”?

David Betz

12.11.2009

Thanks! This got me half way there. The challenge I was given: a reverse ordered list of articles grouped by year, so basically a series of ordered lists separated by headers with the reverse count preserved.

$(document).ready(function() {
 
var totalAll 0;
 $(
'.reversed').each(function() {
  
var children = $(this).children('li');
  var 
totalChildren children.length;
  
totalAll+= totalChildren;
 
});
 $(
'.reversed').each(function() {
  
var children = $(this).children('li');
  var 
totalChildren children.length;
  
children.each(function() {
   
$(this).val(totalAll--);
  
});
 
});
}); 

——-

Too late, comments are closed!

Don’t worry, you can email me or contact me on Twitter.