Content with Style

Web Technique

DOM scripting or how to keep the code clean

by Pascal Opitz on October 27 2005, 04:24

Required knowledge

In this tutorial I want to show up the differences between DOM-Scripting and the “traditional” JavaScript technique using event-handlers embedded into the HTML-code. I'll show a way to have accessible popups, and by showing how to do those, I'll explain the proper use of DOM-scripting. Obviously knowledge of JavaScript is required to get my explanations.

Pseudo-format javascript:

So, what was the old way? Well, let's start with the very old way:

 <a href="javascript:window.open('http://www.google.de',
    'popup','width=200,height=400');">open google</a>

This is really annoying! First of all it's not even a real link. The use of this pseudo-format takes away the possibility of having an action and a location where the link points to. So this is the very old way. And, as you can see, it's code that is not very good when it comes to maintaining it. So that's why for a long time we used the following stuff.

Event handlers as HTML attributes

Yeah, you know what I'm talking about! I mean “onclick”, “onmouseover” and so on, embedded directly into the HTML-tag. So that now our tag would look like this:

 <a href="#" onclick="window.open('http://www.google.de',
    'popup','width=200,height=400');">open google</a>

And maybe, instead of having the whole thing in there, we'd have a function in javascript where we just pass the URL to? Because we open popups in the same size throughout the whole site anyway?

 <script type="text/javascript">

 function pop(url)
 {
  window.open(url,'popup','width=200,height=400');
 }

 </script>

 <a href="#" onclick="pop('http://www.google.de');">open google</a>

That would be better for maintanance, no doubt, but how about accessible? No, it's not! No textbased browser or no system where javascript has been turned-off could open that link. Now how am I going to make that accessible? Well, there's a way!

Accessible popups

The way to do accessible popups is quite an overhead:

 <script type="text/javascript">

 function pop(url)
 {
  window.open(url,'popup','width=200,height=400');
 }

 </script>

 <a href="http://www.google.de" target="_blank"
   onclick="pop('http://www.google.de');return false;">open google</a>

How does this work? Well, first of all it's a simple link with target="_blank". But on top of that we have an event handler with an action inside and a return statement, which quits the click-event. By doing this the browser quits before going to the new location, which would be in another window. But if javascript is off, none of this would happen and just the new location would be opened in a new window.

Shortcut

Still one annoying thing, though: It's to much code to write! So my first approach would be to take a shortcut:

 <script type="text/javascript">

 function pop(url)
 {
  window.open(url,'popup','width=200,height=400');
  return false;
 }

 </script>

 <a href="http://www.google.de" target="_blank"
   onclick="return pop('http://www.google.de');">open google</a>

The saved amount of characters is not to big, but still, if the site is big and you can save typing “false” 300 times you'll be happy about it.
Next point is that I'm annoyed about the possibility to type “www.google.de” in one and a typo like “www.gogole.de” in the other part of the link. Stuff like that ALWAYS happens, and it sucks so much! But that's the first opportunity to use propper DOM-scripting!

“this” or the link as object

Instead of calling the function now with a string as parameter, we'll call it with an object reference:

 <script type="text/javascript">

 function pop(a)
 {
  url = a.getAttribute("href");
  window.open(url,'popup','width=200,height=400');
  return false;
 }

 </script>

 <a href="http://www.google.de" target="_blank"
   onclick="return pop(this);">open google</a>

Here it is, the link acts as object, it has a method that gives back an attribute. That is DOM (Document Object Model). Well, that's fine for the beginning, but still there's two things that really I consider as below the optimum: We have to writre the handler into each link. And we have changed the markup of the document in the HTML-area, probably many times, depending on how many popup-links we have.

Some of the DOM-toolkit

Event-handler just in javascript

The way to apply event-handler in javascript looks like this:

 window.onload = function()
 {
 	alert("window has been loaded now");
 }

It is possible to apply already existing functions as well:

 function alertLoaded()
 {
 	alert("window has been loaded now");
 }

 window.onload = alertLoaded;

The benefit obvoiusly is that we can define handler for HTML-objects without changing their markup. If we can find them, of course!

Navigating the DOM tree

There are two methods to find elements, document.getElementById() and document.getElementsByTagName(). Once the object has been found we can run through the tree up and down by using the object node.parentNode and the array node.childNodes. If you want to get deeper into DOM-scripting you might have a look at the Gecko DOM interface.

The tree-parsing solution

Let's get back back to our little example. We'll make use of document.getElementsByTagName() to change all links with target="_blank" to popup-links without adding any markup to them.

function applyPopups()
{
  a = document.getElementsByTagName("a");

  for(i=0; i<a.length; i++)
  {
    if(a[i].getAttribute("target") && a[i].getAttribute("target") == "_blank")
    {
      a[i].onclick = function()
      {
        url = this.getAttribute("href");
        window.open(url,'popup','width=200,height=400');
        return false;
      }
    }
  }
}

window.onload = applyPopups;

As you can see, you now don't even have the hassle of adding additional markup to your HTML-code, but can apply popup-behaviour by just importing one js-file in the head of the document. Splendid!

Comments

  • Nice article, Pascal!

    Here’s another application to the technique you describe. You can create nice menus automatically from the following code:


    <ul id="menu">
    <li><a href="home.html">Home</a>
    <li><a href="products.html">Products</a>
    </ul>


    What is necessary is to take the URL from the HREF of A tag wrapped with LI and create onClick function on that LI with appropriate HREF. The ID of UL element will allow to find only necessary LI’s and A’s. Doing so will guaranty that if user clicks anywhere on the cell (not only on the A tag text) he will be forwarded to a new page. And the processing can be automated down to onLoad=”processMenu(‘menu’)” in BODY tag. In conjuntion with correct cursor shape set for LI in CSS (to mimic the one when over the link) the overal look and feel will be excellent.

    We use this technique for several years already and it’s proved to work wonderfully.

    by Aleksey Gureev on May 22 2005, 07:30 #

  • hmm, why the hassle?
    Using css and switching the “li” to inline, the “a” within the “li” to block should do the same, right? And you don’t “pollute” the body tag. And would ensure that, if JS is off, it still works on new generation browsers. Does that make sense?

    by Pascal Opitz on May 22 2005, 10:24 #

  • Since the target attribute is not allowed in XHTML 1.0 Strict, would it be better to apply something like class="popupLink" instead?

    by Scott Becker on May 23 2005, 09:48 #

  • I use the rel attribute instead. Rel=”external” for popups is both semantic and human readable… I’ve also got a rel=”choice” which, at runtime, triggers a script to run through and add a little popup icon after the link to open in a new window, allowing people to choose between same and new windows.

    by Mike Stenhouse on May 23 2005, 12:10 #

  • Haahahahaa. Hey, Mike, you seem like a smart guy, can I meet you for a pint? Let’s set up a website!

    I have been using the rel attribute for a couple of things in the past, including image rollovers and other things where I wanted to trick the validator; until I got worried that I don’t follow the idea of the attribute. But your way of using it seems actually close enough to what it’s supposed to be.

    by Matthias on May 23 2005, 17:17 #

  • Er, now anyone who’s not read the about page will be thinking you’re my stalker!

    by Mike Stenhouse on May 24 2005, 23:19 #

  • Pascal, you are right. The same could be established by pure CSS also. You points make sense.

    by Aleksey Gureev on May 26 2005, 10:59 #

  • In fact i always suggest this way to insert pop-ups in a web page.

    Throw into the popup variant and you are done, accessible popup windows for the masses!

    cheers,
    deelan.

    by deelan on May 26 2005, 12:07 #

  • Deelan,
    Your suggested solution is getting used more and more, which is good, and Pascal had mentioned it in his article as well (ok, minus the target=”_blank”, but that’s really a question of strict or transitional xhtml).

    What I like about Pascals approach is, that you can separate content from functionality. The html stays the same, clean and lean. I’m sure instead of the target you could use other ways of determining which links are popups and which stay in the same window, such as an id (don’t forget to keep it unique) or the surrounding html structure.

    Cheers,
    Matthias

    by Matthias on May 26 2005, 14:56 #

  • Deelan:
    Matthias is right about that. you could trigger the same by using any attribute, a surrounding or a childnode element … target _blank is just an example and for sure not best practice for accessible HTML.

    The weak point of way you suggest is the “pollution” with the onclick handler within the markup, and the redundant string for the href, which is exactly what you can get rid of...

    by Pascal Opitz on May 26 2005, 17:02 #

  • great site! I mentioned this on my site today and thought you would enjoy my take on this subject. I wrote a javascript function that makes adding XHTML tags easier. I would like to expand on it. Please let me know what you think. It’s at http://www.heywink.com/files/DOModder.zip you can read about it at http://www.heywink.com/files/DOModder.pdf

    by wink! on June 6 2005, 22:20 #

  • Great article, althought I won’t use it, because I don’t like to pop out windows. As a user, I know how to open a new window when clicking on a link, when I want to…

    Note that the first two old ways are really annoying, because it prevents to allow to drag the link to a tab (in Mozilla or Firefox or custom IE base browser), which is the usual way I use to open a link in another window (that and Ctrl+Click, of course);.

    I also just want to point out two typos:
    propper and getElemet (3 times…)
    HTH.

    by Philippe Lhoste on September 26 2005, 05:52 #

  • Phillipe:
    Thanks for pointing out the possibility with dragging links to a tab (I never thought of that actually).

    Fair enough that you don’t do popups, but in fact the article was more about showing non-intrusive javascript and the popups were just an example. So if you didn’t know about this before I hope you could use bits and bobs.

    For the typos: Shame on me! Removed them.

    by Pascal Opitz on October 27 2005, 04:29 #

  • Keeping the markup hook free:
    Opening pop up windows with no extra markup

    by Thierry on November 8 2005, 09:57 #

  • Thierry … nice one.
    Picking up the discussion above: Is there any reason for using “class” instead of “rel” to trigger what’s popup and what’s not?

    by Pascal Opitz on November 10 2005, 07:11 #

  • Pascal,
    The specs say (about “rel”):
    This attribute describes the relationship from the current document to the anchor specified by the href attribute. The value of this attribute is a space-separated list of link types.
    This section is about link types, it lists their conventional interpretations
    The way I read this, I’d say using “class” would be more appropriate.

    BTW, thanks for the compliment about my article.

    by Thierry on November 16 2005, 23:43 #

  • Lucas: According to the w3c definition for id and class both elements can be used “For general purpose processing by user agents (e.g. for identifying fields when extracting data from HTML pages into a database, translating HTML documents into other formats, etc.)”.

    So scripting wise you have the choice what to do with them. CSS wise there is always the specifity that has to be taken into account. And yes, id has to be unique within the document.

    by Pascal Opitz on April 15 2006, 15:58 #

  • Hi there, great article!
    I have a question, I’ve always used class as a “second” identifier, id for unique and class for group of items, am I wrong?

    I really enjoy the possibility to describe an object with non-intrusive Js (I dont really knew how to name this) using many class identifiers heh.

    Thanks!

    by Lucas Zingano on April 15 2006, 12:30 #

  • I guess then it must be possible as well to combine the lightbox “popup” and the DOM popup to achieve a javascriptless popup with background?

    by Esther on September 18 2007, 10:18 #

  • Esther: The lightbox popup as well as any DOM scripting is JavaScript. However, if you wonder about the possibility of using lightbox popup together with attaching events to the DOM nodes, all without explicit script tags in the body: Yeah, that’s possible for sure.

    by Pascal Opitz on September 21 2007, 03:58 #