Sorting Elements with jQuery

Whilst refactoring a jQuery plugin today, I came across a method that placed a list item into an unordered list at a specific point, so that all the items remained in alphabetic order. This long method seemed completely convoluted and slow to me and I decided that there must be an easier way to keep the list in alphabetical order.

There are existing plugins for sorting elements but I never like to just pile on the 3rd party plugins as that means more javascript files to include in a page. Besides, I was sure it should not be difficult.

It soon occured to me that jQuery has the built-in ability to return the elements as an array, using the .get() method and from there, it was not too long before I had my streamlined code to sort the list element alphabetically:

var mylist = $('ul');
var listitems = mylist.children('li').get();
listitems.sort(function(a, b) {
   var compA = $(a).text().toUpperCase();
   var compB = $(b).text().toUpperCase();
   return (compA < compB) ? -1 : (compA > compB) ? 1 : 0;
})
$.each(listitems, function(idx, itm) { mylist.append(itm); });

I utilise the javascript array.sort method to sort the elements in the array and then using the jQuery append() method,  reorder them in the actual list element.

33 Responses to “Sorting Elements with jQuery”

  1. tim  on March 19th, 2009

    These orders alphabetically nicely, but what would i need to do to make it sort by say class or attribute etc instead of alphabetically..

  2. admin  on March 19th, 2009

    The array.sort function allows you to sort by anything. In my example I am retrieving the text of the element with $(a).text() but I could easily retrieve an attribute and compare that instead $(a).attr(‘id’) etc.

  3. William Fisk  on April 10th, 2009

    Thanks, worked perfectly. Its seemingly quite simple but I couldn’t work out myself how to do it.

  4. javigoile  on June 17th, 2009

    Quick question: I tried your script and it works fine the first time, but if I run it twice (I have a link that orders by price and other by category), don’t know why but it duplicates the result!

    What can I do to avoid this?

    Thanks a lot!

  5. javigoile  on June 18th, 2009

    Ups, my bad! I was having a problem with the selector, that was all, script works like a charm!

    Thank you!

  6. dan  on June 18th, 2009

    @javigoile I am glad to hear you sorted the problem.

  7. Fatih YASAR  on August 11th, 2009

    Hey Dan,
    It’s working perfectly, thank for this post.

  8. Bhat  on September 11th, 2009

    Fabulous…Thanks….

  9. Rich Staats  on November 18th, 2009

    Hey Dan, Thank you so much for this, you made it look so easy. I am trying to take this one step further, if possible. I have a list of names (first name and last name) and would like to have this function sort by last name, without forcing the list to be echoed: {lastname}, {firstname}. ie, Staats, Rich. It would be nice to echo: Rich Staats yet sort by “Staats” instead of “Rich.”

    I attempted my own solution based on the attr comment above. I added a span class to each of the list items and gave it a class of “abc”. I then attempted to sort like so:

    var compA = $(a).attr(‘span.abc’).toUpperCase();
    var compB = $(b).attr(‘span.abc’).toUpperCase();

    That however did not work. Can you possibly point me in the right direction?

    Rich

  10. Rich Staats  on November 18th, 2009

    im sorry i had a typo:

    I added a span class to each of the list items and gave it a class of “abc”

    should read:

    I added a span class to each of the last names within the list items and gave it a class of “abc”

    thanks!

  11. beekermd03  on November 19th, 2009

    This is money, thanks!

  12. dan  on November 19th, 2009

    @Richstaats You were nearly there. It should be something like:

    var compA = $(a).find(‘span.abc’).text().toUpperCase();
    var compB = $(b).find(‘span.abc’).text().toUpperCase();

    the compA and compB is the text you are comparing, so with the above statement I am retrieving the text within the span tag.

    Hope that helps,
    Dan

  13. total13  on November 20th, 2009

    Thank you for your code, it helps me a lot! It’s important to note that the sort method in jquery opbjects only works in version 1.3.2, (and above when released i suppose). I was developing in 1.3.1 and gets an error.

    Thanks again and sorry if english is not good!

  14. total13  on November 20th, 2009

    ups! I realized just now that i did it’s not the same as you proposse (i’ve just copied the return line). Now in jquery 1.3.2 is posible do something like this:

    var listitems = $(‘ul li’);
    listitems.sort(function(a, b) {
    var compA = $(a).text().toUpperCase();
    var compB = $(b).text().toUpperCase();
    return (compA compB) ? 1 : 0;
    })

  15. mark  on December 3rd, 2009

    Anyway you can make it work with decimal numbers?

  16. dan  on December 4th, 2009

    @mark Yes, the array.sort function allows you to sort by anything, just use jQuery to select the information you want to sort by, then compare and return -1 when “a” is to be a lower index than “b”, 0 when they are the same and 1 when “b” is to be a lower index than “a”. For more information, google for ‘javascript array sort’.

  17. kshitiz  on December 18th, 2009

    Hi, I have used your script to make a travel website. but, while doing the sorting of hotel by name system slows down. Script works fine with 20 – 80 hotels. But when list is bigger than 300 hotel it hangs the PC.

    I am using your script to sort divs.

    here is the code

    please help me to speed this up.

    var mylist = $(‘#hiddenresult’);
    var listitems = mylist.children(‘div.result’).get();
    listitems.sort(function(a, b) {
    var compA = $(a).find(“#h_hotelnameandprice”).text().toUpperCase();
    var compB = $(b).find(“#h_hotelnameandprice”).text().toUpperCase();
    return (compA compB) ? 1 : 0;
    })
    $.each(listitems, function(idx, itm) {
    mylist.append(itm);
    });

  18. dan  on December 21st, 2009

    @kshitiz I am not sure there is much that can speed things up when you are dealing with large quantities of elements like that. You best approach would be to re-think the page so that you are not displaying so many results or to do the sorting on the server rather than client.

  19. taktu  on December 29th, 2009

    There is a way to speed it up, by reducing amount of append calls to just one at the very end of the sorting process.

    btw. if anyone would like to get desc sorting just change return line as below:
    return (compA > compB) ? -1 : (compA < compB) ? 1 : 0;

    Great script Dan!

  20. aja328  on January 27th, 2010

    This was awesome!

  21. csw11235  on March 23rd, 2010

    I ran into some complications with this. When I identified the list by class (e.g. $(‘ul.listylist’)) it had a problem where it doubled the list elements every time it was sorted after the first time. However, when I changed it to use an ID (e.g. $(‘#mylistylist’)) it worked just fine.

  22. csw11235  on March 23rd, 2010

    Ach, nevermind – figured out I had a hidden list of the same class later in the page.

  23. jaisonv  on July 20th, 2010

    very thx.. I use this.

  24. rossini  on July 27th, 2010

    I seem to be too dumb to use it.

    I am setting up dynamic content for a UL with the id “listticker”.

    code snippet

    for a number of description/strDateTime variables, I am doing this …

    var neuLI = document.createElement(“li”);
    var neuIMG = document.createElement(“IMG”);
    neuIMG.src = “img/me.png”;
    var neuA = document.createElement(“A”);
    neuA.href = “”;
    neuA.className = “blub”;
    sometext = document.createTextNode(description);
    neuA.appendChild(sometext);
    var neuSPAN = document.createElement(“span”);
    neuSPAN.className = “bla”;
    neuSPAN.innerHTML = strDateTime + “”;
    neuLI.appendChild(neuIMG);
    neuLI.appendChild(neuA);
    neuLI.appendChild(neuSPAN);
    document.getElementById(“listticker”).appendChild(neuLI);

    which should “translate” into the following html code:

    <a HREF=”" rel=”nofollow”>first DESCRIPTION</A>
    first Date and Time
    .
    …further list elements…
    .

    However, I need the UL with ID of “listticker” being sorted by the content of the “span” elements (ie. by date and time).

    I tried to use the following code within the $(document).ready function…

    var mylist = $(“#listticker”);
    var listitems = mylist.children(‘li’).get();
    listitems.sort(function(a, b) {
    top.alert(“I am running”);
    var compA = $(a).find(‘span’).text().toUpperCase();
    var compB = $(b).find(‘span’).text().toUpperCase();
    return (compA compB) ? 1 : 0;
    })
    $.each(listitems, function(idx, itm) { mylist.append(itm); });

    I inserted the top.alert statement, but it does not get called…
    And the list does not get sorted, too. :-)

    Shall I add further commands?

    BTW, I am using jquery 1.2.6 …

    Is there some working demo available?

    Thank you in advance, dear jquery experts….

    Oliver

  25. rossini  on July 30th, 2010

    Dan? Any assistance or hint that you (or anybody) could give? I’d be happy to send you the full source code, if you would like to see it…

    I know that you probably are involved in many projects, but maybe you want to help a poor dumbhead with his code…?!

    Thx in advance,
    Oliver

  26. dan  on July 30th, 2010

    Hi rossini. Sorry, I am rather busy at the moment. I find your mixture of jQuery and traditional javascript confuses things uneccessarily, it is much easier to assemble elements with jQuery:

    var mylist = $(‘#listticker’).append(‘<li><img src=”img/me.png” /><a href=”" class=”blub”>’+description+’</a><span class=”bla”>’+strDateTime+’</span></li>’);

    There are a couple of things wrong with your sorting javascript. Firstly, you are missing a semi-colon after the sort function and before the each statement. Secondly your comparison logic (the return statement) is not correct. This works:

    $(function() {
    var mylist = $(‘#listticker’);
    var listitems = mylist.children(‘li’).get();
    listitems.sort(function(a,b) {
    var compA = $(a).find(‘span’).text().toUpperCase();
    var compB = $(b).find(‘span’).text().toUpperCase();
    return (compA < compB) ? -1 : (compA > compB) ? 1 : 0;
    });
    $.each(listitems, function(idx, itm) { mylist.append(itm); });
    });

    See this demo at JSFiddle

    Hope that helps

  27. Senthil Kumar  on August 1st, 2010

    Thanks dude! Exactly what i was looking for! :-)

  28. rossini  on August 1st, 2010

    Hi Dan, hi all,

    thank you so much for your support. I appreciate it very much.

    Okay, I get closer :-)

    It seems that when having a static UL in the HTML code, it gets sorted as intended.

    But I am clearing that static list and adding new ones on document ready, then trying to sort it…

    $(document).ready(function(){
    var adminrssfeed = “notesfromadmin.xml”;
    $(“#listticker”).empty();
    $.get(adminrssfeed, function(d) {
    $(d).find(‘entry’).each(function() {
    var $item = $(this);
    var description = $item.find(‘description’).text();
    var pubDate = $item.find(‘updated’).text();
    var mychildren = $(‘#listticker’).append(‘‘+description+’‘+pubDate+”);
    });
    });

    var mylist = $(“#listticker”);
    var listitems = mylist.children(‘li’).get();
    listitems.sort(function(a,b) {
    var compA = $(a).find(‘span’).text().toUpperCase();
    var compB = $(b).find(‘span’).text().toUpperCase();
    return (compA compB) ? 1 : 0;
    });
    $.each(listitems, function(idx, itm) { mylist.append(itm); });

    };

    This fills the listticker ul element with new entries from an xml file, but the sorting part doesn’t work. I think, this is because I am appending new elements, but they are not there yet when I try to sort them.

    I can send the full code including the xml file and send that to you if you like.

    Is there something that I can do after appending the elements and before sorting them, to make them sortable? :-)

    Or am I missing something here?

    Thank you in advance,

    Oliver

  29. rossini  on August 1st, 2010

    The .append in the last comment got “interpreted”. The command was:

    var mychildren = $('#listticker').append(''+description+''+pubDate+'');
    
  30. dan  on August 1st, 2010

    @rossini – You need to run the sort within the $.get callback, after you append the items.

    $.get(url, function(d) {
      $(d).find(‘entry’).each(function() {
         //code to append items
       });
       //put sort code here
    });
    

    Remember that AJAX calls are asynchronous so you need to run the code at the right time – after it has finished. Currently it is just trying to sort an empty list

  31. rossini  on August 2nd, 2010

    Hi Dan,

    thank you very much, Dan… I figured it out a few minutes ago by myself… I have to re-write a bit code to make it work the way it’s intended to run… but I can see clearly now the path to heaven.

    Thank you very much for helping me.

    And a brilliant solution, of course. Thx…
    Oliver

  32. Sam  on August 11th, 2010

    Dear smart folks,

    I have been trying to get this working on a wordpress site but I am not having much luck.

    I have a submenu which consists of a list of links. Currently they get generated in order of date, but I just want to have them listed in alphabetical order. I thought maybe I can do this with jquery?

    The submenu div is called #projects-sub-menu

    I have put your code in my js file, and changed the first line to:

    var mylist = $(‘#projects-sub-menu’);

    I can’t get it working though, my list still shows up in order of date. I am a novice and would really appreciate any guidance.

  33. Sam  on August 11th, 2010

    Hi guys, back again. I can’t believe this but I got it working perfectly. Now one remaining question. My issues was that I had specified the incorrect value where it says ‘span’ below:

    var compA = $(a).find(‘span’).text().toUpperCase();
    var compB = $(b).find(‘span’).text().toUpperCase();

    I changed it from ‘span’ to ‘a’ (for hyperlinks) and it worked!

    Now, my remaining issues is that my list 6 columns wide and I is displaying items alphabetically but in horizontal order, not vertical order. Is there any code I can append to it that can make it list the items in vertical order?


Leave a Reply