0

I'd like to sort multi-column list without using a table. I know of solutions for single column lists but I can't seem to find one that sorts on multiple Ul/columns while keeping the list/row items together.

Ultimately I'd like to make something similar to what dropbox has done for displaying files. Yes, Dropbox doesn't use a sortable table. It's a list instead of tr's with a bunch of divs instead of td's.

I don't want to use a table because tables drive me crazy for styling purposes. Also, I don't want to use a plugin (like tablesorter.js) because javascript has a built in sort() function so it can't be that many lines of code.

Anyway, here is a nice single column demonstration taken from another SO question, and the original SO reference.

Basically I'd like to do what's in the fiddle but be able to sort by names, and for example addresses, here's a fiddle building upon this first fiddle where you can see where i'd like to go with this http://jsfiddle.net/trpeters1/De8Ku/955/. As you'll notice, this fiddle can't sort based on the address which is what I'd like find a solution for.

UPDATE With many thanks to eterps (see below) now the fiddle can sort by multiple columns. I'd now like to next include sorting by date. Here is a fiddle which makes an attempt at this but doesn't quite work. You'll notice I tried to convert the innerHTML to a Date() object but this didn't solve this problem. http://jsfiddle.net/trpeters1/De8Ku/983/

In this fiddle, can someone help explain why the sorting of the dates is still just alpha/numerical and not by date?

Community
  • 1
  • 1
tim peterson
  • 23,653
  • 59
  • 177
  • 299
  • If you have a bunch of tabular data you want sorted, then the correct and appropriate solution is a sortable table. I think you're protesting for no really good reason. – Blazemonger Mar 19 '12 at 20:17
  • I didn't get into all the styling things I'd like to do but believe me trying to get a table to work had been a huge pain, also Dropbox doesn't use a table and I think they've got a pretty good solution to displaying lots of tabular data – tim peterson Mar 19 '12 at 20:37

1 Answers1

2

Using the code you provided in your jsFiddle examples, you can add some identifying information to your span tags to differentiate the text into columns. Then you can use that information to do your sort. I altered the jsFiddle example to use a sorting function that will look at whichever column is specified. I'm sure there are more elegant ways of doing this, but it should get you started.

http://jsfiddle.net/De8Ku/976/

Here is the code in case the jsFiddle isn't working or if someone want to edit this answer:

HTML:

<input type="button" id="test" value="sort by names"/>
<input type="button" id="test1" value="sort by address"/>

<ul id="list">
   <li ><span class="name">peter</span><span class="address"> 812 jones st.</span></li>
   <li><span class="name">zack</span><span class="address"> 512 jones st.</span></li>
   <li><span class="name">alex</span><span class="address"> 712 jones st.</span></li>
   <li><span class="name">sue</span><span class="address"> 112 jones st.</span></li>
   <li><span class="name">jenny</span><span class="address"> 912 jones st.</span></li>
</ul>

JS:

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

    var lis = ul.getElementsByTagName("LI");
    var vals = [];

    // Instead of filling an array with list items, 
    // create an array of objects that contain the list item itself, 
    // and the value from the sort-by column
    for (var i = 0, l = lis.length; i < l; i++) {
        vals.push({
            sortFieldVal: lis[i].getElementsByClassName(sortClass)[0].innerText,
            val: lis[i].innerHTML
        });
    }

    // Use a sort function to compare string values of sortFieldVal for each item
    vals.sort(function(a, b) {
        var nameA=a.sortFieldVal.toLowerCase(), nameB=b.sortFieldVal.toLowerCase()
        if (nameA < nameB) //sort string ascending
        return -1 
        if (nameA > nameB)
        return 1
        return 0 //default return value (no sorting)
    });

    if (sortDescending) vals.reverse();

    for (var i = 0, l = lis.length; i < l; i++)
    lis[i].innerHTML = vals[i].val;
}

window.onload = function() {
    var desc = false;
    document.getElementById("test").onclick = function() {
        sortUnorderedList("list", desc, "name");
        desc = !desc;
        return false;
    }

    document.getElementById("test1").onclick = function() {
        sortUnorderedList("list", desc, "address");
        desc = !desc;
        return false;
    }
}​
eterps
  • 14,198
  • 4
  • 35
  • 46
  • hi eterps, one more question if possible: I'd like to build upon your nice work to also include sorting by date. Here is a fiddle which makes an attempt at this but doesn't quite work. You'll notice I tried to convert the innerHTML to a Date() object but this didn't help. http://jsfiddle.net/trpeters1/De8Ku/983/ In this fiddle, might you be able to explain why the sorting of the dates is still just alpha/numerical and not by date? thanks! tim – tim peterson Mar 20 '12 at 04:16
  • And FYI, it is generally frowned upon to unaccept an answer to force a follow-up reply to a new question. It would be just as easy to ask this as a separate question (e.g. "Why does this sort by name, but not by date?"). Or just ask without unaccepting - you'll find that most people will be accommodating to follow-up requests. – eterps Mar 20 '12 at 14:18
  • You need to parse the Date with Date.parse(). Also, some of your new code was putting the wrong values in the sorting object. See the new jsFiddle here: http://jsfiddle.net/eterpstra/QTZPC/2/ – eterps Mar 20 '12 at 15:04
  • hi eterps, sorry to offend you, I'm not that familiar with how SO operates. It has seemed to me that once an answer gets accepted no one ever touches it again. Having a question that doesn't have an accepted answer has seemed to me the only way to trigger people to make comments. Basically, I'm just not familiar with the etiquette or the algorithms SO uses to keep conversations going in the right direction. Thank you for your suggestion/advice. I will re-accept your answer to this question. – tim peterson Mar 20 '12 at 15:07
  • And eterps, thank you again for all your help, your most recent fiddle (Date.parse()) seals the deal, awesome! – tim peterson Mar 20 '12 at 15:15
  • No worries. SO lets you comment at any time, regardless of the status of the question or answer. Also, just wanted to note that jQuery is not used in any of the above solutions, so no need to load the jQuery library unless you are using it elsewhere in your site. – eterps Mar 20 '12 at 17:02