views:

293

answers:

3

I've been playing around trying to get a function that will sort a selection of li tags by their content but currently to no avail (at least no speed/accuracy);

$('.sortasc').live('click',function(){

        var liArr = Array();

        $('#licontainer').children('li').each(function(){
           liArr.push($(this).html());
        });

        liArr.sort(alphaNumSort);

        $(liArr).each(function(){
            var current = this;

            var clone = $('li').filter(function(){return($(this).html()==current);}).clone();

            $('li').filter(function(){return($(this).html()==current);}).remove();

            clone.appendTo('#tempsortbox');

        });

        $('#licontainer').html($('#tempsortbox').html());
        $('#tempsortbox').html('')

    });

It's both slow and not GREAT at sorting. Idealy, it would sort based on the content of a strong tag that resides within the li.

Here's the alphaNumSort function if you're interested (this works a treat its just the crappy html and cloning rubbish that's not really working)

function alphaNumSort(m,n){
try{
    var cnt= 0,tem;
    var a= m.toLowerCase();
    var b= n.toLowerCase();
    if(a== b) return 0;
    var x=/^(\.)?\d/;

    var L= Math.min(a.length,b.length)+ 1;
    while(cnt< L && a.charAt(cnt)=== b.charAt(cnt) &&
    x.test(b.substring(cnt))== false && x.test(a.substring(cnt))== false) cnt++;
    a= a.substring(cnt);
    b= b.substring(cnt);

    if(x.test(a) || x.test(b)){
        if(x.test(a)== false)return (a)? 1: -1;
        else if(x.test(b)== false)return (b)? -1: 1;
        else{
            var tem= parseFloat(a)-parseFloat(b);
            if(tem!= 0) return tem;
            else tem= a.search(/[^\.\d]/);
            if(tem== -1) tem= b.search(/[^\.\d]/);
            a= a.substring(tem);
            b= b.substring(tem);
        }
    }
    if(a== b) return 0;
    else return (a >b)? 1: -1;
}
catch(er){
    return 0;
}

}

Cheers

A: 

If you want to sort it with javascript, you need a method/function to sort it. And you need to choose when it will be sorted: loading, clicking on a button, etc...

The other possibility is to sort before sending the html: it depends on your server language. Php, java, asp, etc... ? But you can use the same link to find the best algorithm for your needs.

enguerran
+7  A: 

I'm not completely sure what your alphaNumSort function does, but a simple string comparison may be enough.

var li = $('#licontainer li').get();

// sort the list items based on the contents of a nested strong tag
li.sort(function(a, b) {
    a = $('strong', a).text();
    b = $('strong', b).text();

    // you may want to process the text values further here, perhaps
    // running it through $.trim, reducing whitespace sequences with
    // a regular expression, or lower- or upper-casing letters to
    // make the comparison case-insensitive.

    return (a < b) ? -1 : ((a > b) ? 1 : 0);
});

// reinsert the list items in their new order
$('#licontainer').append(li);

This should be considerably faster than your temporary list method, as it performs fewer DOM operations. The use of native string comparisons should also be a fair bit faster than your current sorting algorithm, but if it is doing something specific that I have missed update the return statement to utilize it (keeping the preceding lines).

return alphaNumSort(a, b);

If this is still too slow you could likely improve performance even more by hiding the list before manipulating it, preventing the browser from performing unnecessary repaints.

var li = $('#licontainer').hide().find('li').get();

// ...

$('#licontainer').append(li).show();
Alex Barrett
+1 innerText is definitely a better approach than innerHTML. The strings might still need some processing though, how about trimming whitespace in case nesting markup is inconsistent? Also `Array.sort` is non-standard, it should be `Array.prototype.sort.call`.
bobince
Thanks for the feedback and the +1. `Array.sort` is most definitely standard, but it is certainly less compatible than using `Array.prototype`. I will update my answer to reflect your comment, adding text post-processing as an exercise for the reader :)
Alex Barrett
+1 IMHO `li.get().sort` is more intuitive for readers of the code.
Roatin Marth
Thank you Roatin Marth, I agree with you. I've updated the answer to use your suggestion. I added `get()` to the initial variable assignment, as `sort()` operates in-place.
Alex Barrett
That's a sweet little snippet man, does the job royally. I implemented my alphanumeric sorting so it sorts both numerically 1,2,15,17,27 rather than 1,15,17,2,27 as well as sorting text. It's quick, and in like 5 lines! Thanks a bunch!
Joel
Nice answer..................
Crescent Fresh
A: 
var sortList = function () {
    var ul = document.getElementsByTagName("ul"),
    ol = document.getElementsByTagName("ol"),
    sort = function (x) {
        var a, li;
        for (a = 0; a < x.length; a += 1) {
            li = x[a].getElementsByTagName("li");
            li = li.sort();
            x[a].innerHTML = li.join("");
        }
    };
    sort(ul);
    sort(ol);
};