Tuesday, January 26, 2010

JQuery: TableSorter AJAX Zebra Fix

Just had a day of yuckky dealing with a 'bug' / nonfeature of JQuery's Tablesorter dealing with an AJAX call. Problem was that once I make the ajax call, the zebra striping goes all to hell.

This was due, it turns out, to 2 things:
1. I had a hidden/openable div in one of the table cells;
2. I didn't have the update call after the ajax return.

IMPORTANT: TO SEE FULL CODE, CUT AND PASTE. STUPID LAYOUT OF THIS BLOG. The text/code is really there, the viewable div below prevents it from displaying. Just cut and paste the code fragments below to see the full code...

So, step one:


function actionCount() {
$.ajaxSetup({
cache: false,
type: "POST",
success: function(html) {
$("#myprojectstable").trigger("update");
// console.log("Inside Success function..");
}
});
var orgid = $("#orgID").val();
var projidlist = <%= self.fields.projidlist %>;
$.post("ActionsCountJSON", { projids: projidlist }, function(raw){
var rawData = raw['resultSet'];
var rawList = raw['resultListing'];
for (f in rawData) {
var divloc = "#pActionsProjid" + f;
var divobj = $(divloc);
divobj.html(rawData[f]);
divloc = "#pActionDataProjid" + f;
var divobj = $(divloc);
divobj.html(rawList[f]);
};
$("#myprojectstable").trigger("sorton", [0,0]);
$("#myprojectstable").trigger("applyWidgets");
$("#myprojectstable").trigger("update");
//console.log("done with AJAX POST.");
//stripe("myprojectstable");
}, 'json');
}



Having the update there made the widget trigger after the ajax returned, a vital thing because otherwise tablesorter doesn't know the underlying data has changed. After I had this, it resorted after the ajax came back.

Next, I had a widgets: [zebra] in my document ready function, but this widget wasn't working right.

So, I replaced it with my own widget by specifying widgets: ['zebraKJR']
then creating that widget as:



$.tablesorter.addWidget(
{
id: "zebraKJR",
format: function(table)
{
var even = false;
// console.log("zebraKJR called.");
// if arguments are provided to specify the colours
// of the even & odd rows, then use the them;
// otherwise use the following defaults:
var evenColor = arguments[1] ? arguments[1] : "#fff";
var oddColor = arguments[2] ? arguments[2] : "#cde4ff";

if(table.config.debug) { var time = new Date(); }

//var tbody = $("tr:visible",table.tBodies[0]);
// by definition, tables can have more than one tbody
// element, so we'll have to get the list of child
// <tbody>s
var tbodies = table.getElementsByTagName("tbody");
// and iterate through them...
// for (var h = 0; h < 1tbodies.length; h++) {
for (var h = 0; h < 1; h++) {
// find all the <tr> elements...
var trs = tbodies[h].getElementsByTagName("tr");
// ... and iterate through them
for (var i = 0; i < trs.length; i++) {
if (trs[i].id != 'stripeMe') {
// console.log("SKIPPING thru tr's, h="+h+", i="+i+", len="+trs.length+", trs data:"+trs[i].id); //innerHTML
continue;
}
// console.log("COLORING thru tr's, h="+h+", i="+i+", len="+trs.length+", trs data:"+trs[i].id); //innerHTML

trs[i].style.backgroundColor = even? evenColor : oddColor;
// avoid rows that have a class attribute
// or backgroundColor style
if (true) { //(! hasClass(trs[i]) && ! trs[i].style.backgroundColor) {
// get all the cells in this row...
var tds = trs[i].getElementsByTagName("td");
// and iterate through them...
for (var j = 0; j < tds.length; j++) {
var mytd = tds[j];
// avoid cells that have a class attribute
// or backgroundColor style
if (true) { //(! hasClass(mytd) &&! mytd.style.backgroundColor) {
mytd.style.backgroundColor = even ? evenColor : oddColor;
}
}
}
// flip from odd to even, or vice-versa
even = ! even;
}
}
}
});



That's it!

I also have a parser method for parsing text out of HTML tags:


// add parser through the tablesorter addParser method
$.tablesorter.addParser({
// set a unique id
id: 'noUrlSorter',
is: function(s) {
// return false so this parser is not auto detected
return false;
},
format: function(s) {
// format your data for normalization
beforeString = trim(s);
t1 = s;
t2 = t1.replace(/\"/ig,"");
t3 = t2.replace(/(<([^>]+)>)/ig,"");
t4 = t3.toLowerCase();
//alert(" t1="+t1+
// ",t2="+t2+
// ",t3="+t3+
// ",t4="+t4);
//console.log("parsing, b4="+beforeString+", returning: "+t4);
return t4
},
// set type, either numeric or text
type: 'text'
});

1 comment:

YuriKolovsky said...

Thanks for the post, but it's way too complicated to even bother using it.
Usually in jquery these things are made into plugins and simplified to one call that does something magical :P