Rough Guide To The DOM (part 2)

Use the new DOM for image swaps, table generation, frame navigation and form validation.

Digging Deeper

In the first part of this article, I took you through the basics of navigating an HTML document via the DOM, and explained the various methods and collections available to you. If you understood all that (and I hope you did), you should now have a pretty clear idea of how to manipulate a typical HTML document, and change interface elements on the fly.

Over the next few pages, I’m going to dig a little deeper into the DOM, with illustrations of how the DOM interfaces with tables, forms, images and frames. I’ll also be discussing some of the methods available to add (and modify) nodes to the DOM tree through JavaScript, and point you to some of the Web’s better resources on the subject.

Let’s get cracking!

Making The Swap()

The first item on the agenda today is an illustration of how you can use the DOM to accomplish one of the most popular dHTML applications - the image swap. Take a gander at the following HTML document:

<html>
<head>
</head>

<body>

<a href="http://www.melonfire.com/" onMouseOver="javascript:imageSwap();"
onMouseOut="javascript:imageSwap();"><img id="logo" src="logo_n.gif"
width=50 height=50 border=0></a>

</body>
</html>

Now, I’ve set this up so that “mouseover” and “mouseout” events on the image are handled by the JavaScript function imageSwap(). This function is responsible for swapping the image each time an event occurs - so let’s take a look at it.

<script language="JavaScript">
var normal = "logo_n.gif";
var hover = "logo_h.gif";

function imageSwap()
{
var imageObj = document.getElementById("logo");
var imageSrc = imageObj.getAttribute("src");

	if (imageSrc == normal)
		{
		imageObj.setAttribute("src", hover);
		}
	else
		{
		imageObj.setAttribute("src", normal);
		}
}
</script>

If you remember what I taught you last time, none of this should come as a surprise. I’ve first defined the “normal” and “hover” state images, and then created a function called imageSwap(), which is called whenever the mouse moves over and out of the image.

The imageSwap() function obtains a reference to the image via its ID, and then obtains the current value of the image’s “src” attribute. It then checks the value against the values of the “normal” and “hover” variables, and changes the image source appropriately.

Turning The Tables

Next up, tables. Take a look at the following HTML document, which contains a table with two rows, three cells each.

<html><head></head><body><table border="1" cellspacing="5"
cellpadding="5"><tr><td>R1, C1</td><td>R1, C2</td><td>R1,
C3</td></tr><tr><td>R2, C1</td><td>R2, C2</td><td id="r2c3">R2,
C3</td></tr></table></body></html>

Now, when navigating through a table, there’s one important point to be aware of - from the DOM vie, a table must be treated as though it included an additional <tbody> tag immediately after the <table> tag and before the <tr> tags. Adding this to the equation, the page above now looks like this:

<html><head></head><body><table border="1" cellspacing="5"
cellpadding="5"><tbody><tr><td>R1, C1</td><td>R1, C2</td><td>R1,
C3</td></tr><tr><td>R2, C1</td><td>R2, C2</td><td id="r2c3">R2,
C3</td></tr></tbody></table></body></html>

The usual DOM navigation rules now apply, as the following example demonstrates. This script drills down to the last cell of the second row and alters both the background colour of the cell and the text string within it.

<script language="JavaScript">

// get to the cell
// you could also use
// var cellObj =
document.childNodes[0].childNodes[1].childNodes[0].childNodes[0].childNodes[
1].childNodes[2];

var cellObj = document.getElementById("r2c3");

// get to the text within the cell
var cellTextObj = cellObj.childNodes[0];

// set background colour
cellObj.setAttribute("bgcolor", "red");

// and text
cellTextObj.data = "Second row, third column";

</script>

Well-Formed

Another very popular use of JavaScript is form validation - verifying the data entered into an online form. In the next example, I’ll be using the DOM and some simple JavaScript to ensure that the checkbox is ticked and the email address entered into the text field is in the correct format. Here’s the form

<html>
<head>
</head>

<body>

<form action="somescript.cgi" method="post" onSubmit="return check();">
Email address:
<br>
<input id="email" type="text" name="email" size="30">
<br>
<input id="spam_me" type="Checkbox" name="spam_me">Yes, I want you to send
me megabytes of useless advertisements via email. I love buying crummy
products from people who probably flunked kindergarten.
<br>
<input type="submit">
</form>

</body>
</html>

and here’s the validation script.

<script language="JavaScript">

function checkEmail()
{
// get to the field
var obj = document.getElementById("email");

// value of field
var str = obj.value;

// define pattern to match email address
var pattern =
/^([a-zA-Z0-9])+([\.a-zA-Z0-9_-])*@([a-zA-Z0-9_-])+(\.[a-zA-Z0-9_-]+)+/;

// match the string to the pattern
var flag = pattern.test(str);

	if(!flag)
	{
	alert ("Please enter a valid email address");
	return false;
	}
	else
	{
	return true;
	}

}

function checkSpam()
{
// get to the field
var obj = document.getElementById("spam_me");

// checkbox ticked?
	if (obj.checked)
	{
	return true;
	}
	else
	{
	alert ("Please check the box");
	return false;
	}
}


function check()
{
// perform validation and submit form if all is well
	if(checkEmail() && checkSpam())
	{
	return true;
	}
	else
	{
	return false;
	}
}

</script>

As you can see, the form is submitted only after receiving a positive (true) result from the JavaScript function check(). This function, in turn, calls the functions checkEmail() and checkSpam(),which first obtain references to their respective form elements and then check their values for validity.

In The Frame

It’s also interesting to see how the DOM works with frames. Consider the following example, which sets up two frames, “left.html” and “right.html”.

<html>
<head>
</head>

<frameset  cols="20%,*">
    <frame name="left" src="left.html" scrolling="auto" frameborder="no">
    <frame name="right" src="right.html"  scrolling="auto" frameborder="no">
</frameset>

</html>

In order to illustrate how to navigate across frames, I’m going to write a simple script which changes the background colour of the right frame when the appropriate link is clicked in the left frame. Here’s the right frame,

<html>
<head>
</head>

<body id="body">
</body>
</html>

and here’s the left frame - note how each link calls the changeFrameBackground() function with a color as parameter.

<html>
<head>
</head>

<body>

<a href="javascript:changeFrameBackground('red')">Red</a>
<br>
<a href="javascript:changeFrameBackground('blue')">Blue</a>
<br>
<a href="javascript:changeFrameBackground('green')">Green</a>
<br>
<a href="javascript:changeFrameBackground('black')">Black</a>

</body>
</html>

Finally, let’s take a look at the function which does all the work.

<script language="JavaScript">

var bodyObj = top.right.document.getElementById("body");

function changeFrameBackground(col)
{
bodyObj.setAttribute("bgcolor", col);
}

</script>

Since this is a frameset, it’s necessary to prefix the document.getElementById() method call with a reference to the appropriate frame. This prefix is necessary to identify to the DOM which frame is being called, and to obtain a reference to the correct document tree.

Once a reference to the right frame’s <body> tag is obtained, changing the frame’s background colour is a simple setAttribute() away.

Branching Out

The DOM also comes with a bunch of built-in methods designed to manipulate the DOM tree, adding and removing nodes from it on the fly. As you’ve already seen, a node on the DOM tree could be either an HTML tag or a text fragment - and the DOM comes with methods to add both these types of nodes to the tree, through program code.

I’ll begin with the createElement() method, which is used to create a new HTML tag. The following code snippet creates an <img> tag as a node, and assigns it the name “imageObj”.

<script language="JavaScript">
var imageObj = document.createElement("img");
</script>

Once the node has been created, attributes can be assigned to it using the setAttribute() method. For example, the code snippet

<script language="JavaScript">
imageObj.setAttribute("src", "logo_n.gif");
imageObj.setAttribute("width", "50");
imageObj.setAttribute("height", "50");
</script>

is equivalent to the tag

<img src="logo_n.gif" width="50" height="50">

Once the node has been created, the next order of business is to add it to the document tree - a task accomplished by the appendChild() method. The appendChild() method is used to append the newly-created node to a specific location in the tree.

The following code snippet would attach the “imageObj” node as a child of the element identified by “heading1”.

<script language="JavaScript">
document.getElementById("heading1").appendChild(imageObj);
</script>

Dumbing It Down

Just as you can create HTML tags as nodes, the DOM also allows you to create new text nodes on the tree with the aptly-named createTextNode() method. Here’s an example:

<script language="JavaScript">
var insultObj = document.createTextNode("Could you *be* any dumber?");
</script>

Again, the appendChild() method comes into play to attach the new text node to the appropriate branch of the document tree.

<script language="JavaScript">
document.getElementById("heading1").appendChild(insultObj);
</script>

Let’s see how this plays out in a real-life example. I’ve put together a simple HTML page, which contains nothing except a set of <p> tags and some JavaScript code. The JavaScript will create a new text node and a new <img> tag and add them to the document tree as children of the <p> tag, using the code snippets I’ve just demonstrated.

<html>
<head>
</head>

<body>

<p id="heading1"></p>

<script language="JavaScript">

// set up the image
var imageObj = document.createElement("img");
imageObj.setAttribute("src", "logo.gif");
imageObj.setAttribute("width", "50");
imageObj.setAttribute("height", "50");
document.getElementById("heading1").appendChild(imageObj);

// set up the text node
var insultObj = document.createTextNode("Could you *be* any dumber");
document.getElementById("heading1").appendChild(insultObj);

// use this for testing
var pObj = document.getElementById("heading1");

// returns IMG
// alert (pObj.childNodes[0].nodeName);

// returns #text
// alert (pObj.childNodes[1].nodeName);

</script>

</body>
</html>

Although the page contains only a single <p> tag, running the script will add an <img> tag and a line of text to the document tree, which will be immediately visible in the browser.

Of course, the DOM comes with a bunch of other methods as well - here’s a brief list, together with an explanation of their function.

removeNode() - remove a node (and/or all its children) from the document tree

replaceNode() - replace a node with another node

cloneNode() - duplicate an existing node

swapNode() - swap the positions of two nodes in the document tree

insertBefore() - insert a node at a specific point in the document tree

Most of these are self-explanatory, and they’re not used all that often, so I don’t plan to discuss them in detail - they’re included here for the sake of completeness.

Conclusions

Should you be interested in learning more about the DOM, there are a number of resources available to you online. Here’s a brief list:

The official W3C DOM specifications, at http://www.w3.org/DOM/

Mozilla.org developer resources, at http://www.mozilla.org/docs/ and http://www.mozilla.org/docs/web-developer/

DOM sample code at http://www.mozilla.org/docs/dom/samples/

An interesting article on transitioning from proprietary DOMs to the W3C standard, at http://sites.netscape.net/ekrockhome/standards.html

A structural (logical) view of the DOM, at http://www.xml.com/1999/07/dom/xml_dom.gif

An XML introduction to the DOM, at http://www.xml101.com/dom/

And finally, before I go, a final comment. While the new DOM may appear to be far less flexible and easy to use than the proprietary models developers have been used to, the fact remains that it offers one very important advantage: standardization. This DOM has been written in such a manner that every element on a page is finally available to the developer via standard navigation rules, and can be manipulated using standard object methods and properties.

In the short run, it may be difficult - even frustrating - to re-code Web pages as per the new DOM; however, I believe that the effort is well worth putting in, as it immediately ensures that your pages will be viewable across all standards-compliant browsers. It should be noted that much of the confusion in the past (and the resulting profusion of proprietary DOM interfaces) was due to the lack of clear direction from the W3C; now that a DOM specification has been finalized and released, future versions of all the major browsers should support it completely, and we should hopefully see an end to browser incompatibilities that have plagued developers in the past.

Here’s hoping!

Note: All examples in this article have been tested on Mozilla (build 18). Examples are illustrative only, and are not meant for a production environment. YMMV!

This article was first published on 26 Apr 2001.