Show-n-Tell Thursday

Sorting categories by count

Yet more XML and AJAX, what can I say, it's just so much fun playing around with this stuff.

While in Sweden we were talking about how a real "nice to have" would be to be able to get a list of categories sorted by the number of documents in each category. As has become patently obvious I am not a Notes client guy, but on the browser this is really pretty simple. There are two steps that we need to go through.

So what we're aiming to get is a list of the categories that are in this blog and then sort them by the number of documents within each category.

Step 1 - Getting the data
This is where the AJAX comes in. Recently I have switched over to using prototype for all of my AJAX calls, it's a really powerful (and free) javascript library which handles all of your AJAX needs and some more besides. You may have noticed the new "Now Playing" block over on the left which is using prototype to make a request every 5 minutes to see what I'm listening to in iTunes.

So to get the XML for the categories I do the following:
function getCategories()
{
var a=$H(
{
collapseview: "true",
count: 1000
}
);
var myAjax = new Ajax.Request(
'http://www.11tmr.com/11tmr.nsf/BlogByCategoryCount?readviewentries',
{method: 'get', parameters: a.toQueryString(), onComplete: outputCategories}
);
}

To me this is why prototype is so great, I just need to give it a URL and some parameters and it will go and handle everything else for me including browser issues. The final URL we're building here is:
http://www.11tmr.com/11tmr.nsf/BlogByCategoryCount?readviewentries&count=1000&collapseview=true
When the URL is loaded then prototype will call the "outputCategories" function and pass in the response from the URL (whether that be XML or HTML or text doesn't matter at this point).

Step 2 - Sorting the Data
OK, now we have the XML of the view, one entry per category thanks to the "collapseview" URL parameter. The attributes of each entry tell us the number of blog entries under each category (the "children" attribute) and also the total number of documents for the category (i.e. the number of blog entries plus the number of comments as well) in the "descendants" attribute:


This next bit I can't claim credit for, instead I pass on thanks to Breaking Par Consulting who posted a great tip about sorting multi dimensional arrays in javascript. The pattern is to create a class function, in this case it has three properties - Category Title, Count and Number of Comments. We loop through the XML and create a category object for each category and place the new object into an array. After the array has been populated it's just a matter of calling the sort method but making sure that you give it a function to define the sort rule:
...
for (i=0; i {
cat = getInnerText(results[i].getElementsByTagName("entrydata")[0]);
count = parseInt(results[i].attributes[2].value, 10);
comments = parseInt(results[i].attributes[3].value, 10) - count;
aCats.push(new category(cat, count, comments));
}

aCats.sort(sortCount);
...


function category(title, count, comments)
{
this.Title = editReplace(title, "\n", "");
this.Count = count;
this.Comments = comments;
}

/*
sorting pattern courtesy of Breaking Par
http://www.breakingpar.com/bkp/home.nsf/0/87256B280015193F87256C8D00514FA4
*/
function sortCount(a, b)
{
var x = a.Count;
var y = b.Count;
return ((x > y) ? -1 : ((x < y) ? 1 : 0));
}

The Result
Hopefully that makes sense. If not then go and have a look at the final result and follow through the whole code there.