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
Here’s another application to the technique you describe. You can create nice menus automatically from the following code:
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 #
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 #
class="popupLink"
instead?by Scott Becker on May 23 2005, 09:48 #
by Mike Stenhouse on May 23 2005, 12:10 #
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 #
by Mike Stenhouse on May 24 2005, 23:19 #
by Aleksey Gureev on May 26 2005, 10:59 #
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 #
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 #
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 #
by wink! on June 6 2005, 22:20 #
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 #
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 #
Opening pop up windows with no extra markup
by Thierry on November 8 2005, 09:57 #
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 #
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 #
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 #
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 #
by Esther on September 18 2007, 10:18 #
by Pascal Opitz on September 21 2007, 03:58 #