Seperating HTML, CSS and Javascript – unobtrusive javascript
November 16, 2008
Please note!! I have shamelessly stolen this article from my old and (even if I do say so myself) rather boring blog. So please ignore the terrible writing style! I’ll rewrite this article in the future, but until then, I present you with version 1.0
In todays world of ‘standards this’, ‘accessibility that’ and ‘ajax the other’, it can be a little overwhelming and confusing. How, for example, are you supposed to be able to add in all of this lovely AJAX scripting without being allowed to add javascript anywhere on your page to keep it accessible?!
Luckily, there is a way. Read on if you would like to know how this black magic is done…
First things first, let’s decide exactly what files we will need for the tutorial. There are three parts to a web page. The structure (xhtml), the styling (css), and thirdly, and behaviour (javascript). These should be three distinct parts. An HTML tag such as
Click me
is very naughty indeed.
Your (x)html should look as if it has no styling and no javascript applied to it (other than the ‘class’ and ‘id’ elements applied to a tag). How, then, are you supposed to get anything to do anything? The good news is that you’re ‘allowed’ to include css and javascript from other files, keeping your html looking tidy.
So, how to get event handers (onclick) etc from the external file into the tags of you html. Well there is a brilliant technology called the DOM (document object model). Using this, it is possible to find and edit the tags and their attributes. There are two great functions to do this with, getElementById and getElementsByTagName. Using these, the possibilities are endless! What you must do it load the html, then get the browser to do a little work and update the markup to do the dynamic things which you want it to do.
One function that they seemed to overlook was getElementsByClassName, which is quite strange considering the other two functions. Luckily, there are other developers in the world who have already noticed this, so there are many already written. I use Robert Nyman’s getElementsByClassName function.
So, to modify the tags, you first search for them using one of these javascript functions. Then, when you have found the tag (or group of tags) which you want to edit, you edit them with javascript. It’s really not as scary as it sounds if you write functions to do this for you, and luckily, I have written a function to do this for you. It has quite a few options, including changing the class name, adding html to the element (adding more functionality might need more explaination), and ofcourse adding the onclick attribute.
// usage: injectBehaviour ('myClass', {'onclick':functionName})
// options in the array are:
// onclick
// addclassname
// replaceclassname
// addtitle
// replacetitle
// htmlbefore
// htmlafter
// htmlreplace
//
// if both add* and replace* are specified, 'replace' takes precidence
//
// if htmlbefore / htmlafter are specified, they will be added before
// or after the original innerHTML or the htmlreplace specified
function injectBehaviour(className, options)
{
var elements=getElementsByClassName (document, "a", className);
for (var i=0;i
Notice how in the onclick part of the function, it is a slightly more complicated than the other parts. This is so that you can either pass a 'hard coded' function (for example 'alert("Hello, world")') or pass a 'dynamic' function whose parameters might change depending on the element (if for example building a dynamic list). If the latter is true, I have surrounded the execution block with a try/catch statement just incase there are any syntax errors in the text you supply. To pass the element to this function, simply use the word 'this' and it will work. I realise that this is quite difficult to explain/understand in writing, so here is a coded example.
Click me!
injectBehaviour ("makeMeSayHello", {'onclick':'alert("The element with id "+this.id+" is saying hello!")'});
I know, this is a bit of a pointless script, but you get the idea.
Now, here's the problem: You want to call this function LOADS of times, but you only have one onLoad handler for the body tag. What do you do?!??! Here's your answer (aren't you lucky!)
// allows for multiple onload functions to be added to the
// document. instead of using use
// addOnload (function).
function addOnload(func) {
var oldOnload = window.onload;
if (typeof oldOnload == "function") {
window.onload = function() {
if (oldOnload) {
oldOnload();
}
func();
}
}
else {
window.onload = func;
}
}
So now all you do at the bottom of your page is this
So to sum up, never again will you be putting onAnything handlers ANYWHERE in your html, will you!
P.S. That doesn't mean you can use this either!
Naughty