Wednesday, September 27, 2006

Playpen #3 - Changing Your Stripes

You know what they say about Leopards... well at least you can get a table to change its stripes with a bit of DOM scripting.

It's a fairly trivial problem, but seeing as I'm pretty green when it comes to unobtrusive JavaScript, it's somewhere to start!

The Playpen #3 page shows off the table, which has a new class added on alternate rows, and defines a new background colour in the CSS. OnMouseOver will change the class again, to give another colour. But I'm having real trouble resetting the original class/colour onMouseOut... It's probably because the DOM is changed on the fly, and the original (not moused over) state of the alternate row is never actually "stored" on the page. If anyone has any suggestions, I'd be very interested to hear.

For the record, my stripeTables script looks like this:

function stripeTables() {
if (!document.getElementsByTagName) return false;
var tables = document.getElementsByTagName("table");
for (var i=0; i<tables.length; i++) {
var odd = false;
var rows = tables[i].getElementsByTagName("tr");
for (var j=0; j<rows.length; j++) {
if (odd == true) {
addClass(rows[j],"altrow");
odd = false;
} else {
odd = true;
}
}
}
}

addLoadEvent(stripeTables);

And this is highlightRows:

function highlightRows() {
if(!document.getElementsByTagName) return false;
var rows = document.getElementsByTagName("tr");
for (var i=0; i<rows.length; i++) {
var rowclass = rows[i].getAttribute("class");
rows[i].onmouseover = function() {
addClass(this,"highlight");
}
rows[i].onmouseout = function() {
this.setAttribute("class" , "rowclass[i]");
}
}
}
addLoadEvent(highlightRows);
I thought getting the Class attribute and storing as rowclass would allow me to reset it to what it was before the onMouseOver event, but sadly the table rows become unstripey once they are moused over!

The only other way I can think of doing it is writing some sort of subtractClass script to complement addClass, but seeing as this will almost certainly involve hideous regular expressions, I'm rather shying away from that.

Anyone have any ideas what I'm doing wrong?

1 comment:

Anonymous said...

Several things are amiss here. First of all I was very confused about the example you showed above (which is in Domscripting the book). This is very verbose and has an extra if in there that is not needed.

Here is the logic:

- loop trough all tables
- loop through rows in the table
- highlight every second row
- add a handler to the row to add another class when the mouse is over it.
- add a handler to remove that class.

The first step of the logic is broken, as a real data table should have a thead, where you explain what the colums are, a tbody which is the data and a tfoot which is the overall sum of the lot.

Therefore you need to loop through tbody instead of table as you don't want to alter the table header row.

The odd/even test is not needed either as you are looping through an array. Therefore you can use the counter and the modulo "%" to stripe the table.

So all in all:
function stripe(){
var bodies = document.getElementsByTagName('tbody');
for (var i=0;i<bodies.length;i++){
var rows = document.getElementsByTagName('tr');
for (var j=0;j<rows.length;j++){
if(j % 2 == =0 ){
addClass(rows[j],'odd');
}
rows[j].onmouseover = function(){
addClass(this,'over');
}
rows[j].onmouseout = function(){
removeClass(this,'over');
}
}
}
function addClass(o,c){
o.className = o.className?o.className+' '+c:c;
}
function removeClass(o,c){
var re = new RegExp('\s?'+c);
o.className = o.className.replace(re,'');
}
}

This is quick and dirty though, I'd do it with event delegation or a real addHandler function, but it should get you on the way