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'
});