Using jQuery for evil
Sometimes you find a tool that’s not just good for run-of-the-mill, intended-purpose work, but also for fixing up some bad situations. jQuery is one such tool.
Some work I’m currently doing involves presenting nicely styled pages to the user of a web site. The html I have to work with is not always ideal and needs to be massaged. Because I’m dealing with templates, it’s often simply impossible for me to change the html – I can only try to modify the framework around the bits of html I’m given.
Enter jQuery.
Provided the html I get is more or less xhtml compliant, I’ve got a Document Object Model (DOM) I can work with. Using jQuery, I’ve found that I can manipulate this to my heart’s desire.
Let’s say I end up with an table which has an extra row between the header row and the first actual row of data. No problem!
$(document).ready(function() { $('#mytable tr:nth-child(2)').remove(); });
And that’s it! Of course you may get a flicker of the incorrect display because we’re making the change only when the DOM is completely built, but we’re not really choosy in this situation.
Let’s try something a bit harder. How about reformatting a table which contains a single column for debits and credits; the debits formatted with a red <FONT> tag. And before you ask, yes, I’m serious.
We want this table to have a separate column for debits and credits. Again, enter jQuery.
$(document).ready(function() { // first, deal with the headers var cell = $('#mytable tr:eq(0) td:eq(2)'); // look at the second cell (contains debits/credits) var w = cell.attr('width').substr(0, cell.attr('width').length-1); // I know width is a percentage cell.attr('width',''+(w/2)+'%'); // half the width cell.text('Credits').before('<td align="right" width="'+w/2+'%">Debits</td>'); // split Debits and Credits header // now deal with each non-header row $('#mytable tr:not(:first)').each(function() { $(this).children('td:eq(2)').before('<td align="right"> </td>'); // insert the new column var redVal = $(this).children('td:eq(3)').html(); // get current column value if (redVal && (redVal.toUpperCase().indexOf('COLOR=RED') > -1 || redVal.toUpperCase().indexOf('COLOR="RED"') > -1)) // if it's red { redVal = $(this).children('td:eq(3)').children('font').text(); // get the actual value to write $(this).children('td:eq(2)').html('<span style="color: red;"> '+redVal+'</span>'); // write to the debit column $(this).children('td:eq(3)').html('nbsp;'); // erase the credit column } }); });
Now this doesn’t give me beautiful xhtml, and I’m never going to feel happy about how this works, but it does the job.
Fun stuff.
I would exhaust every work around to this approach before taking this approach. This approach is like a book editor realizing that a printed book still needs edits, but it would be too much work to re-print the books, so he crosses out words and writes the edits in the margins of the book by hand. Its an ugly substitute to doing things the correct way. Not to mention, this approach will cause any new programmer on this project terrific head aches, when they can figure out why the last row in mytable is always disappearing.
I totally, 100% agree with you. Perhaps I didn’t make it clear that this was my last option.
I would have much preferred to make changes to the code that created and delivered the html, but that wasn’t an option. It was simply far too difficult and problematic to change most of the html that is delivered to the browser. To put it simply, a big black box dumps html into my templates. For example, while the templates I can edit define the tags, the rows and cells are beyond my control.
So yes, not an ideal option, but unfortunately about the only workable one.