views:

362

answers:

4
+1  Q: 

Sorting <li> tags

I have a a and I would like to sort my list alphabetically (I don't want caps to matter) according to a class named "name". How would I do this?

<ul class="column">
  <li>
    <table>
      <tr>
        <td class="name" >Name of Item</td>
      </tr>
      <tr>
        <td>Content</td>
      </tr>
      <tr>
        <td>morecontent</td>
        <td>morecontent</td>
      </tr>
    </table>
  </li>
  <li>
    <table>
      <tr>
        <td class="name" >Another name of item</td>
      </tr>
      <tr>
        <td>Content</td>
      </tr>
      <tr>
        <td>morecontent</td>
        <td>morecontent</td>
      </tr>
    </table>
  </li>
</ul>

Thanks

+5  A: 

Using jQuery, this should do it:

function sort() {
    $($('ul.column>li').get().reverse()).each(function(outer) {
        var sorting = this;
        $($('ul.column>li').get().reverse()).each(function(inner) {
            if($('td.name', this).text().localeCompare($('td.name', sorting).text()) > 0) {
                this.parentNode.insertBefore(sorting.parentNode.removeChild(sorting), this);
            }
        });
    });
}

The above is a little dense though, so if you want to understand what's going on, let's break it down line-by-line:

function sort() {

    //get each <li> which is a child of <ul class="column">
    //for each element in the results, execute a function
    //also, we reversed the order (e.g. start at the bottom and go up
    $($('ul.column>li').get().reverse()).each(function(outer) {

        //this is the current <li> we're running against
        var sorting = this;

        //get the same set of elements again in their current state,
        //so we can figure out where to put this one
        $($('ul.column>li').get().reverse()).each(function(inner) {

            //get the inner text of the <td class="name">
            //for the item we're trying to replace,
            //and for the current item in the inner loop
            //use localeCompare to compare the two strings alphabetically
            if($('td.name', this).text().localeCompare($('td.name', sorting).text()) > 0) {

                //if the one we're trying to sort goes after the current one
                //alphabetically, remove it from its current position
                //and insert it after the current one
                this.parentNode.insertBefore(sorting.parentNode.removeChild(sorting), this);
            }
        });
    });
}

We can make it a little more reusable by passing in the selector for the list and the key:

sort('ul.column>li', 'td.name');

function sort(list, key) {
    $($(list).get().reverse()).each(function(outer) {
        var sorting = this;
        $($(list).get().reverse()).each(function(inner) {
            if($(key, this).text().localeCompare($(key, sorting).text()) > 0) {
                this.parentNode.insertBefore(sorting.parentNode.removeChild(sorting), this);
            }
        });
    });
}

Do keep in mind this requires jQuery, so you'll need a reference to it in your <head>:

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"&gt;&lt;/script&gt;

And this function should be called at some point in the page after the list is written in the HTML.

Rex M
Your solution is very flexible.
NawaMan
+1  A: 
NawaMan
This will not work if there are nested lists inside the list to be sorted.
Rex M
You are right. I've use to use 'find', I will change it to children. Thanks for point that out.
NawaMan
A: 

Just seconding the jQuery response above, have a look at this tutorial: http://www.shopdev.co.uk/blog/sortable-lists-using-jquery-ui/

For semantics, you might be better off also placing the classname inside the actual <li> tag.

The use of a table inside a list aside though, you may want to post an example page to help further.

SuperRoach
Thanks, I already Im using JQuery so this will be easy to add. :)
PHPNooblet
A: 

Here's another approach, stealing ideas from the other answers given so far (also requiring jQuery):

function sort(elementSelector, valueSelector, ascending) {
  var sign = ascending ? -1 : 1;
  var elements = jQuery(elementSelector);
  elements.each(function() {
    this.sortKey = jQuery(valueSelector, this).text();
  });
  var sorted = elements.get();
  sorted.sort(function(a, b) {
    var keyA = a.sortKey;
    var keyB = b.sortKey;
    return sign * ((keyA < keyB) - (keyA > keyB));
  });
  elements.parent().append(sorted);
}

sort('.column>li', '.name', true)
David