By dougoftheabaci


2009-07-16 01:20:59 8 Comments

I'm a bit out of my depth here and I'm hoping this is actually possible.

I'd like to be able to call a function that would sort all the items in my list alphabetically.

I've been looking through the jQuery UI for sorting but that doesn't seem to be it. Any thoughts?

9 comments

@Mikhail 2016-10-24 15:05:57

HTML

<ul id="list">
    <li>alpha</li>
    <li>gamma</li>
    <li>beta</li>
</ul>

JavaScript

function sort(ul) {
    var ul = document.getElementById(ul)
    var liArr = ul.children
    var arr = new Array()
    for (var i = 0; i < liArr.length; i++) {
        arr.push(liArr[i].textContent)
    }
    arr.sort()
    arr.forEach(function(content, index) {
        liArr[index].textContent = content
    })
}

sort("list")

JSFiddle Demo https://jsfiddle.net/97oo61nw/

Here we are push all values of li elements inside ul with specific id (which we provided as function argument) to array arr and sort it using sort() method which is sorted alphabetical by default. After array arr is sorted we are loop this array using forEach() method and just replace text content of all li elements with sorted content

@Elon Zito 2016-02-01 09:42:41

Put the list in an array, use JavaScript's .sort(), which is by default alphabetical, then convert the array back to a list.

http://www.w3schools.com/jsref/jsref_sort.asp

@Salman A 2015-05-07 08:23:33

If you are using jQuery you can do this:

$(function() {

  var $list = $("#list");

  $list.children().detach().sort(function(a, b) {
    return $(a).text().localeCompare($(b).text());
  }).appendTo($list);

});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>

<ul id="list">
  <li>delta</li>
  <li>cat</li>
  <li>alpha</li>
  <li>cat</li>
  <li>beta</li>
  <li>gamma</li>
  <li>gamma</li>
  <li>alpha</li>
  <li>cat</li>
  <li>delta</li>
  <li>bat</li>
  <li>cat</li>
</ul>

Note that returning 1 and -1 (or 0 and 1) from the compare function is absolutely wrong.

@Buzut 2014-04-17 14:04:05

@SolutionYogi's answer works like a charm, but it seems that using $.each is less straightforward and efficient than directly appending listitems :

var mylist = $('#list');
var listitems = mylist.children('li').get();

listitems.sort(function(a, b) {
   return $(a).text().toUpperCase().localeCompare($(b).text().toUpperCase());
})

mylist.empty().append(listitems);

Fiddle

@Jacob van Lingen 2014-08-12 09:35:08

$('#list').empty() --> mylist.empty() would be better. No need to touch the DOM again.

@Buzut 2014-08-12 11:50:11

Absolutely, I just fixed it!

@Chad Johnson 2014-12-10 23:12:57

This does not work in Internet Explorer (tested with version 10).

@Buzut 2014-12-11 13:00:21

I just tested with IE11 and in fact, it doesn't work. But SolutionYogi's code didn't work neither under IE11… Did that work for you?

@Quirkles 2014-03-15 03:49:26

I was looking to do this myself, and I wasnt satisfied with any of the answers provided simply because, I believe, they are quadratic time, and I need to do this on lists hundreds of items long.

I ended up extending jquery, and my solution uses jquery, but could easily be modified to use straight javascript.

I only access each item twice, and perform one linearithmic sort, so this should, I think, work out to be a lot faster on large datasets, though I freely confess I could be mistaken there:

sortList: function() {
   if (!this.is("ul") || !this.length)
      return
   else {
      var getData = function(ul) {
         var lis     = ul.find('li'),
             liData  = {
               liTexts : []
            }; 

         for(var i = 0; i<lis.length; i++){
             var key              = $(lis[i]).text().trim().toLowerCase().replace(/\s/g, ""),
             attrs                = lis[i].attributes;
             liData[key]          = {},
             liData[key]['attrs'] = {},
             liData[key]['html']  = $(lis[i]).html();

             liData.liTexts.push(key);

             for (var j = 0; j < attrs.length; j++) {
                liData[key]['attrs'][attrs[j].nodeName] = attrs[j].nodeValue;
             }
          }

          return liData;
       },

       processData = function (obj){
          var sortedTexts = obj.liTexts.sort(),
              htmlStr     = '';

          for(var i = 0; i < sortedTexts.length; i++){
             var attrsStr   = '',
                 attributes = obj[sortedTexts[i]].attrs;

             for(attr in attributes){
                var str = attr + "=\'" + attributes[attr] + "\' ";
                attrsStr += str;
             }

             htmlStr += "<li "+ attrsStr + ">" + obj[sortedTexts[i]].html+"</li>";
          }

          return htmlStr;

       };

       this.html(processData(getData(this)));
    }
}

@SolutionYogi 2009-07-16 01:24:28

Something like this:

var mylist = $('#myUL');
var listitems = mylist.children('li').get();
listitems.sort(function(a, b) {
   return $(a).text().toUpperCase().localeCompare($(b).text().toUpperCase());
})
$.each(listitems, function(idx, itm) { mylist.append(itm); });

From this page: http://www.onemoretake.com/2009/02/25/sorting-elements-with-jquery/

Above code will sort your unordered list with id 'myUL'.

OR you can use a plugin like TinySort. https://github.com/Sjeiti/TinySort

@Amir 2010-06-30 06:00:26

Can the last line be replaced with $(listitems).appendTo(mylist); ?

@Nathan Strong 2010-12-29 19:19:15

H. L. Menken has a quote that describes this solution: "For every problem, there is a solution that is simple, elegant, and wrong." This process runs in O(n^2) time. It's not noticable with relatively short lists, but on a list containing over 100 elements it takes 3-4 seconds to finish sorting.

@Johann Philipp Strathausen 2011-01-04 11:01:43

@Nathan: About "For every problem, there is a solution that is simple, elegant, and wrong." - well, a wrong solution is not elegant.

@Jane Panda 2011-09-29 14:55:32

Something can be elegant and intriguing to watch, but still fail. Elegance doesn't imply success.

@Jon Winstanley 2012-03-07 09:50:42

TinySort doesn't work in IE for me.

@Samurai Soul 2014-11-11 15:27:58

This solution is not wrong. It answers the question. The OP did not specify that he needed to sort a list of more than 100 items. If his list will never be longer than 100 items this solution is perfectly acceptable. +1 for pointing out that the solution is slow, -1 for declaring a solution that meets the requirements as 'wrong'.

@Jason 2015-05-04 19:54:16

This solution is more general - if I just wanted to sort a list of values, I would use Josh's solution. But if I want to sort an array of DOM elements based on some attribute of those elements, this solution is far superior.

@Dylan Valade 2016-03-10 20:01:09

This worked for me but I did add trim() to handle whitespace. return $(a).text().toUpperCase().trim().localeCompare($(b).text().t‌​oUpperCase().trim())

@Ken 2019-04-30 11:06:14

Documentation for localeCompare can be found here: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…

@Ry- 2019-06-10 15:34:23

@NathanStrong: Which process runs in O(n^2) time?

@Jeetendra Chauhan 2012-01-12 16:44:44

$(".list li").sort(asc_sort).appendTo('.list');
//$("#debug").text("Output:");
// accending sort
function asc_sort(a, b){
    return ($(b).text()) < ($(a).text()) ? 1 : -1;    
}

// decending sort
function dec_sort(a, b){
    return ($(b).text()) > ($(a).text()) ? 1 : -1;    
}

live demo : http://jsbin.com/eculis/876/edit

@Jules Colle 2012-03-15 04:46:48

This is the best answer. I even like it in one single line like this: $(".list li").sort(function(a, b){return ($(b).text()) < ($(a).text());}).appendTo('.list');. One remark though: .text() should be .text().toUpperCase()

@patg 2013-03-21 12:06:43

Unfortunately this solution doesn't work in IE whilst PatrickHecks answer below works in all browsers.

@Doug Domeny 2013-11-01 21:14:59

Beware of the selector! ".list li" will select all descendent LI tags, not just the immediate children.

@mroncetwice 2014-12-17 19:46:14

@DougDomeny is right. Better to call $(".list").children(), if possible, or set up the selector with immediate child relationship like $(".list > li")

@mroncetwice 2014-12-17 20:20:11

BTW Here's a link to a fiddle i made using this answer. I set up the code as an all-in-one function: jsfiddle.net/mroncetwice/t0whh6fL

@Salman A 2015-05-07 08:04:42

This answer is wrong. It does not return 0 when text is same.

@PatrickHeck 2012-07-05 06:34:01

To make this work work with all browsers including Chrome you need to make the callback function of sort() return -1,0 or 1.

see http://inderpreetsingh.com/2010/12/01/chromes-javascript-sort-array-function-is-different-yet-proper/

function sortUL(selector) {
    $(selector).children("li").sort(function(a, b) {
        var upA = $(a).text().toUpperCase();
        var upB = $(b).text().toUpperCase();
        return (upA < upB) ? -1 : (upA > upB) ? 1 : 0;
    }).appendTo(selector);
}
sortUL("ul.mylist");

@Daud 2012-08-28 19:54:56

Shouldn't all the li elements be removed from ul.myList before appending the sorted li elements ?

@Konga Raju 2012-11-21 07:12:32

how can I print reverse

@Doug Domeny 2013-11-01 21:58:36

@Daud, the LI elements don't need to be explicitly removed.

@Doug Domeny 2013-11-01 22:01:30

Using .localeCompare would be an improvement for non-ASCII characters.

@bowserm 2015-01-05 18:23:30

@DougDomeny, why don't the li elements need to be explicitly removed?

@Doug Domeny 2015-01-05 22:32:00

@bowserm, the appendTo method moves the DOM elements rather than copying them.

@Josh Stodola 2009-07-16 02:14:18

You do not need jQuery to do this...

function sortUnorderedList(ul, sortDescending) {
  if(typeof ul == "string")
    ul = document.getElementById(ul);

  // Idiot-proof, remove if you want
  if(!ul) {
    alert("The UL object is null!");
    return;
  }

  // Get the list items and setup an array for sorting
  var lis = ul.getElementsByTagName("LI");
  var vals = [];

  // Populate the array
  for(var i = 0, l = lis.length; i < l; i++)
    vals.push(lis[i].innerHTML);

  // Sort it
  vals.sort();

  // Sometimes you gotta DESC
  if(sortDescending)
    vals.reverse();

  // Change the list on the page
  for(var i = 0, l = lis.length; i < l; i++)
    lis[i].innerHTML = vals[i];
}

Easy to use...

sortUnorderedList("ID_OF_LIST");

Live Demo →

@Rudism 2011-10-28 13:57:45

One problem that I found with this approach is that, since it's only the text that's being moved around, if you associate data to the DOM nodes using jQuery.data prior to sorting, those associations are now pointing to the wrong nodes after the sort.

@Josh Stodola 2011-10-28 15:38:46

@Rudism If you're using jQuery, refer to SolutionYogi's answer below

@Raynos 2012-01-16 12:51:03

Note that var lis = ul.children should suffice here (and is far more efficient). Also note that lis[i].textContent is preferred (as it's more efficient and get's the actual text).

@Josh Stodola 2012-07-07 05:25:10

Attention down-voters: I would like to encourage you to run some tests before you make a haphazard judgement. This is not as bad as it looks, believe me!

@gregers 2012-09-25 08:35:41

Moving elements with innerHTML is a bad solution because they are not the same elements after sorting. All existing references to the elements are lost. All event listeners bound from JavaScript are lost. It would be better to store the elements instead of innerHTML, use a sort function (vals.sort(function(a, b) {return b.innerHTML < a.innerHTML;})) and appendChild to move elements.

@nottinhill 2012-10-24 12:28:20

Buhuuu innerHTML ! Don't use that. It's Microsoft Proprietary stuff and was never acknowledged by the W3C.

@Alnitak 2013-01-25 22:45:04

IMHO this is a horrible answer. It's perfectly possible to rearrange DOM nodes without serialising them and deserialising them again, and without destroying any attached properties and/or events.

@Federico 2013-04-30 00:32:50

If you want to sort <li><a href="1.html">One<a></li> type lists by the content within the <a></a> tag, simply change this line var lis = ul.getElementsByTagName("LI"); to var lis = ul.getElementsByTagName("a");

@mroncetwice 2014-12-17 22:54:17

This works fine if you have anything but text inside your list-items. Otherwise it gets confused and doesn't sort correctly.

@Coded Container 2015-08-03 19:17:58

It really only makes sense if you are just using one tag inside of another but if you are using A tags you cannot simply search for the a tags because you could have some lited items that are not links.

@Matthew 2015-10-26 18:24:38

... but if you were to use jQuery, how would you do it?

@Nick Bedford 2017-05-03 23:57:52

This answer is disastrous for DOM elements that have state attached (i.e events and data). The functions Node.removeChild() and and Node.insertBefore() exist for a reason.

@Crashalot 2019-06-25 00:02:16

This is a more robust answer that preserves data and attributes: stackoverflow.com/questions/304396/…

Related Questions

Sponsored Content

55 Answered Questions

[SOLVED] How do I check if an element is hidden in jQuery?

61 Answered Questions

[SOLVED] How to check whether a checkbox is checked in jQuery?

58 Answered Questions

[SOLVED] How do I redirect to another webpage?

79 Answered Questions

[SOLVED] How do I remove a particular element from an array in JavaScript?

  • 2011-04-23 22:17:18
  • Walker
  • 5841626 View
  • 7285 Score
  • 79 Answer
  • Tags:   javascript arrays

86 Answered Questions

[SOLVED] How do JavaScript closures work?

34 Answered Questions

[SOLVED] How do I sort a dictionary by value?

14 Answered Questions

[SOLVED] jQuery/JavaScript: accessing contents of an iframe

40 Answered Questions

[SOLVED] Setting "checked" for a checkbox with jQuery?

15 Answered Questions

[SOLVED] "Thinking in AngularJS" if I have a jQuery background?

16 Answered Questions

[SOLVED] How do I find out which DOM element has the focus?

  • 2009-01-30 20:21:31
  • Tony Peterson
  • 596826 View
  • 1190 Score
  • 16 Answer
  • Tags:   javascript dom

Sponsored Content