all things web and not web

allskonar

There is a bit of a learning curve to writing unobtrusive Javascript and to obfuscate matters even further the internet is filled with bad javascript examples, which is one of the reasons why Javascript has such a terrible reputation. My intent here is to go through my learning curve on strapping events on to the dom tree, which I think is the biggest conceptual barrier for writing unobtrusively Javascript. I hope that these examples will cushion the entry into writing Javascript unobtrusively and also lure someone to suggest better ways and help me achieve the ideal. At some point during my evolution I started using libraries such as prototype which I highly recommend but there are others good Javascript libraries such as jquery, dojo, rico and the list goes on.

My examples are bare-bones and only meant for explaining the concept. The samples have two links which if Javascript is enabled alert a text box displaying its href attribute but if Javascript is not enabled it degrades to display the document that the link is pointed to.

Unobtrusive Javascripting is basically just a separation of behavior from the HTML markup, similarly to how CSS stylesheets separated layout instructions from the html markup. There are many benefits to unobtrusive Javascripts and I will highlight two:
  • It makes Graceful Degradation easy simply because if javascript is not enabled on the browser the links will simply just go to the documents they are pointed at.
  • HTML markup become much cleaner and more manageable.

HTML: Example 1


<html>
  <head>
    <title>Example 1</title>
    <script src="example_1.js" type="text/javascript"></script>
  </head>
  <body>
    <h1>Example 1</h1>
    <ul id="links">
      <li><a href="link_1.html">link 1</a></li>
      <li><a href="link_2.html">link 2</a></li>
    </ul>
  </body>
</html>

JS: Example 1


function addLoadEvent(func) {
  var oldonload = window.onload;
  if (typeof window.onload != 'function') {
    window.onload = func;
  } else {
    window.onload = function() {
      oldonload();
      func();
    }
  }
}

My introduction to Unobtrusive Javascript came from Jeromy Keith’s domscripting book in which I got the addLoadEvent function which I believe originated with Simon Willison, the addLoadEvent function allows you to stack functions to the window.onload event que.

addLoadEvent(bootstrapLinks);

The addLoadEvent function is necessary to be able to load .js code from the head of the html document which is one of the first elements on the dom tree. This allows you to stack functions that will be executed once the window.onload event fires which is when the dom tree is ready.


function bootstrapLinks(){
  ul = document.getElementById("links");
  links = ul.getElementsByTagName("a");
  for(var i=0;i&lt;links.length;i++){
    links[i].onclick = doSomething;
  }
}


function doSomething(){
  alert(this.href);
  return false;
}

This code simply grabs an element through the id loops through a elements in there and attaches an onclick event handler to which in this case only alerts the href attribute. The return false is to prevent the browser from following the link.

Now that works fine but it’s so two years ago, and there is the problem of having to wait for the dom tree to be ready which is after everything else has loaded which can take some time especially if there are images and such. The next step does not solve this problem but it makes it a bit more modern and also utilizes the prototype library.

HTML: Example 2

The only thing that changed in the HTML source is adding the reference to the prototype.js file.


<script src="prototype.js" type="text/javascript"></script>

JS: Example 2


Event.observe(window, 'load', bootstrapLinks);


function bootstrapLinks(){
  $$("ul#links a").each(
    function(value){
      value.onclick = doSomething;
    }
  );
}


function doSomething(){
  alert(this.href);
  return false;
}

But we still have to wait for the domtree to load. This is something that was driving me nuts especially when writing code for sites with advertising and image heavy. Then I ran into a very smart Javascript guru by the name of Dan Webb and when I expressed this concern he educated told me about lowpro.js which is a library he built and extends the prototype library.

All you have to do is swap out the Element.observe(.....) with Event.onReady(bootstrap_links); and we are done.

HTML: Example 3

Adding a reference to lowpro.js

<script src="lowpro.js" type="text/javascript"></script>

JS: Example 3


Event.onReady(bootstrapLinks);


function bootstrapLinks(){
  $$("ul#links a").each(
    function(value){
      value.onclick = doSomething;
    }
  );
}


function doSomething(){
  alert(this.href);
  return false;
}

This is only skimming the top. There are loads of other cool stuff you can do.

Leave a Reply

 
allskonar Powered by Mephisto