1

Possible Duplicate:
How may I sort a list alphabetically using jQuery?

I'm using jQuery to come to the rescue for a limited CMS setup.

I need to sort an ordered list alphabetically, but then I also need to be able to place "special" list items at the top of the list and sort again only those special items descending by their "optional" numerical value.

For example if this was my original markup:

<ul>
    <li class=" ">C</li>
    <li class=" ">A</li>
    <li class=" ">B</li>
    <li class=" ">E</li>
    <li class=" ">D</li>
    <li class="3">Z</li>
    <li class="6">Y</li>
    <li class="14">X</li>
</ul>

... I would want jQuery to sort it so this would be the resulting DOM content:

<ul>
    <li class="14">X</li>
    <li class="6">Y</li>
    <li class="3">Z</li>
    <li class=" ">A</li>
    <li class=" ">B</li>
    <li class=" ">C</li>
    <li class=" ">D</li>
    <li class=" ">E</li>
</ul>

If sorting by a class value is not possible or is overly convoluted, perhaps I could use the following markup structure instead:

<ul>
    <li><span class="numerical">3</span><span class="alphabetical">B</span></li>
</ul>

Does anyone know what jQuery code would allow me to do this? Would I need to run a series of nested "each" actions and "insertAfter" and "insertBefore" functions that somehow compare values? I would think there is a better way, but I'm not sure where to begin my research.

I'm open to any and all suggestions. I'll also be trying to figure this out on my own in the meantime, but I'm still a jQuery rookie so I doubt I'll find the right code on my own :)

Thanks!!

Community
  • 1
  • 1
LearnWebCode
  • 1,361
  • 3
  • 12
  • 22
  • Can you use `data-*` attributes instead of classes to signify list item values? – Vadim Jan 25 '13 at 22:28
  • Great question. I'm not familiar with data-* attributes, but I would wonder if jQuery can access those attributes' values if the browser that the jQuery is running in doesn't usually recognize the data-* attribute (IE7/8?). I'll look into that, thanks! – LearnWebCode Jan 25 '13 at 22:30
  • @JohnKoerner - It's close, but I also want to tack on a second reordering after the initial JS ordering. I want to reorder only select elements numerically, once the alphabetical sorting has completed. – LearnWebCode Jan 25 '13 at 22:32
  • @LearnWebCode http://caniuse.com/dataset – wirey00 Jan 25 '13 at 22:54
  • IIRC, class names cannot start with a number. Or at least not in CSS class selectors. `data-*` attributes seem more appropriate here, since those numbers don't really "classify" the elements. – Mattias Buelens Jan 25 '13 at 23:18

1 Answers1

4

You need a comparator function, and a way to rearrange the elements. Plugins are available which given the former will do the latter for you, although if the elements are the sole children of a single parent it's pretty easy (see below).

For your comparator, you'll need something which can be given a pair of your <li> elements, and tell you which comes first:

function myCompare(a, b) {
    var cls_a = parseInt(a.classList, 10);
    var cls_b = parseInt(b.classList, 10);

    cls_a = cls_a || -1 ;   // make blank class == -1
    cls_b = cls_b || -1 ;   //   ditto

    if (cls_a === cls_b) {
        var str_a = a.innerText || a.textContent;
        var str_b = b.innerText || b.textContent;
        return str_a.localeCompare(str_b);
    } else {
        return cls_a - cls_b;  // numeric descending sort
    }
}

and for rearranging:

var $el = $('li');
var $ul = $('ul');
$el.sort(myCompare);  // from above
$el.each(function() {
    $ul.append(this);
});

The .each loop works by just taking each sorted item, and adding it to the end of the <ul> - when there's none left, it's done.

Shorter versions of the above are possible, e.g.:

$('li').sort(myCompare).appendTo($('ul'));

See this jsfiddle

Alnitak
  • 334,560
  • 70
  • 407
  • 495
  • Wow, thanks for the incredible help! Your code looks great. sort() is part of the jQuery library, correct? Or is a plugin needed to use sort(). I'm not trying to be 110% spoon fed, but the JS Fiddle doesn't seem to reorder any of the elements. I tried to analyze what's going on and I'm not sure what could be off except for maybe sort() is not available by default? – LearnWebCode Jan 25 '13 at 23:08
  • @LearnWebCode no, it's the default JS `Array.sort` function, which works because the jQuery object `$('li')` is actually an array. The fiddle works for me on Chrome 24 (resulting in X Y Z A B C D E). – Alnitak Jan 25 '13 at 23:10
  • There I go assuming we need to use jQuery for everything and ignore regular JS functions :) Thanks!! – LearnWebCode Jan 25 '13 at 23:12
  • It looks like it works perfectly in Webkit (Chrome, Safari), but for some reason it's not working in Firefox, but that's a Browser compatibility issue, not a ordering logic question, thanks!!) – LearnWebCode Jan 25 '13 at 23:13
  • @LearnWebCode note that I've used jQuery for the resulting reordering, but there's no jQuery functions inside the comparator – Alnitak Jan 25 '13 at 23:13
  • @LearnWebCode see update - Firefox needs `.textContent` instead of `.innerText` - that's the downside of not using `$(a).text()` inside the comparator! – Alnitak Jan 25 '13 at 23:15
  • Very interesting! Reminds us of one of the big reasons we love jQuery (browser nuances like that). Thanks for the code solution and wealth of information. – LearnWebCode Jan 25 '13 at 23:23