Previous: Understanding JavaScript Events Next: JavaScript and HTML Forms

Introducing the Document Object Model

The this keyword is also an insidious harbinger of a concept that you must grasp before you get too deep into forms—the Document Object Model (DOM). The DOM extends the concept of objects—which you learned about in "Introduction to JavaScript"—until it covers the documents that you're creating in XHTML and working with in JavaScript. In other words, it makes the document itself into objects, which you can then use for JavaScript.

You've just seen an example of the DOM in action. In the most recent example, you saw the following as the event handler for an <input> element:

onchange="checkPhone (document.myForm.phoneNumber.value)"

That series of references inside the function call—document.myForm.phoneNumber.value—is a reference to the DOM. Beginning with the first object name, document, you then work through a number of objects that have been created in the course of the XHTML authoring for this page. First is the myForm object, which holds all the different elements' named objects; then the phoneNumber object, which stores a number of properties for that particular <input> element; and finally the value property of phoneNumber, where the number entered by the user is stored.

It turns out that the DOM also enables you to work with a set of properties between a function call and a function without actually passing any values between the two. Listing 1 is an example of this—notice that neither the function nor the function call requires any parameters. That's because the form data is stored in the DOM, which can be accessed using the correct object syntax.

Listing 1 Working Directly with Your Document's Object Properties

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Passing the Pointer</title>
<meta http-equiv="Content-Script-Type" content="text/javascript">
<script>
<!-- Begin hiding
function compute()
{
  var myNum = document.myForm.userEntry.value;
  myNum = eval(myNum)
  var myResult = myNum + 100;
  document.myForm.result.value = myResult;
  return;
}
// End hiding -->
</script>
</head>

<body>
<h1>Computing Form Data:</h1>

<form name="myForm">
Enter a number: <input type="text" name="userEntry" size="5" /> <br />
Here's the result: <input type="text" name="result" size="5" /> <br />
<input type="button" name="Calc" value="Calc" onclick="compute()" />
</form>

</body>
</html>

Here's how this works:

  1. The user enters a number in the userEntry text box.

  2. Then, when the user clicks the Calc button, the compute() function is invoked.

  3. The function looks up the value of that user entry and assigns it to myNum. Next, it accesses a built-in function, eval(), which evaluates that entry into a number. (Otherwise, it would think the value is text, even though we asked for a number. )

  4. Some arithmetic happens and the answer is assigned to myResult.

  5. myResult is assigned to the value property for the result entry box that's down in the form. The answer automatically appears in the result entry box, and hence is made visible to the user. (This is the same example you saw back in Figure 18.1.)

One thing to watch out for when you're working on this sort of script is when to use the value property and when to ignore it. In most cases, if you're trying to assign something to a particular element with a form, you'll need to use the value property. That's because the named element—say, userInput—has more than just a value associated with it. It also has a type property, for instance, which was set in the original <input> element. So, you can't just use document.form.userInput = x; because userInput is an object, not a property.

NOTE

The DOM has only recently been standardized by the W3C, and Internet Explorer, Netscape, and other browsers have varying implementations of it. Throughout this chapter and the next, I'll try to touch on only cross-platform DOM issues (those that work in both browsers). The online chapter "Adding Dynamic HTML" will offer some platform-specific discussion of other DHTML issues, though.

Understanding Scope and Pointers

One of the issues that can be something of a pain with the DOM is constantly referring to items by their full DOM paths. In general, you need to start at the highest object and move through them, with a period between each one, to get down to a particular property or method. In fact, we've already been using a shortcut. The highest-level object is actually window, so most of our references in the previous section could have looked like this (or something similar) :

window.document.form.userInput.value

As it turns out, though, these paths have something called a scope, which means you can use a shorthand within certain boundaries. Because our scripts aren't affecting any other windows at this stage, we can start with the document object because the current window is assumed.

Along with scope comes another interesting concept, called the pointer. In essence, a pointer is a variable that holds the location of an object. This allows us to cut down the amount of typing we do by assigning a variable to a particular object's path:

function compute()
{
  var theForm = document.myForm;
  var Num = theForm.userEntry.value;
  Num = eval(Num)
  var Result = Num + 100;
  theForm.result.value = Result;
  return;
}

With this simple change to Listing 1, we're able to substitute theForm for document.myForm in each of the object references, which makes life just a little bit easier.

These assignments don't have to happen up top, either. Instead, you could create the pointer in the transaction between the function call and the function. First, consider the function call:

<form name="myForm">
...other elements...
<input type="button" name="Calc" value="Calc" onclick="compute(myForm)" />
</form>

Notice that this is a little different from Listing 1, because now you're going to pass the name of the current form to the function. Because of scoping, you don't have to use the entire DOM path to myForm—because you're in myForm, you can go ahead and simply use myForm in the function call. Now you have to rewrite the function to accept the value and create a pointer:

function compute(theForm)
{
  var Num = theForm.userEntry.value;
  Num = eval(Num)
  var Result = Num + 100;
  theForm.result.value = Result;
  return;
}

Creating the pointer isn't tough at all. All you have to do is give the pointer a name in the parentheses following the function name and you're set. When the function is called, the pointer is created and it's assigned the location of the form. Now, when you access objects and values using that pointer, you can work with them just as if you were using the entire DOM path.

Working with High-Level Objects

So far what we've dealt with are form objects, and we'll get back to those later in this chapter. In the meantime, however, you may be interested to see some of the other DOM objects that you can use in your scripting. In particular, let's take a look at the window object, the location object, and the document object.

The window Object

The window object is something you're already familiar with, even if you don't know it. One familiar method of the window object is the alert() method, which you've seen in sample scripts up until now. The full reference to that method is window.alert(), but unless you're trying to open an alert for another window, scoping allows you to drop the full reference. What alert() does is pop up a dialog box that must be dismissed—by clicking the OK button—before anything else can happen in that window. A string in the parentheses determines what text will appear in the alert dialog box.

As with any other object, the window object has both properties and methods. For the most part, the properties can only be read—you can't change many of them, because the window already exists. Those properties include name (in the title bar), length (number of frames in the window), self (which points to the current window), and status. This last one can actually be used to change the Web browser's status line, which is the little description line at the bottom of the window. Here's an example:

<a href="products.html" onmouseover="status='See our full line of products'" onmouseout="status=''">Products</a>

The window object offers a number of methods that you can use to change things about the window. These include both alert() and the eval() methods, which you've been introduced to. The eval() method, which we used to turn a string into a number, can actually be used to turn any string into JavaScript code, not just into a number.

Other methods that you can use with the window include confirm(), which, like alert(), pops up a dialog box with the enclosed string as its message. Instead of just an OK button, however, the user can also choose a Cancel button. If Cancel is clicked, a value of false is returned; if OK is clicked, true is returned. For example:

var keepGoing = confirm("Do you want to continue?");

The prompt() method is also similar to alert() and confirm(), but it's used to receive a value from the user. You can include both a string for the dialog box text and an optional sample value:

var numberGuess = prompt("Enter a number", 5);
var emailAddress = prompt("Enter your e-mail address", "myadd@fakecorp.com");

The open() method can be used to open a new window, and you can include parameters to govern how that window is opened and what URL it displays. To open a window and display a particular URL, simply use window.open("URL").

The resizeTo() method is a fun one—you can automatically resize a browser window to a particular width and height in pixels. For instance, if your site is best viewed in 800x600, you might opt for a line such as this:

<body onload="window.resizeTo(800,600)">

Along with those properties and methods, the window object has a number of subobjects, such as location, document, and history. The first two have their own sections coming up, but history is worth looking at here. You can use the history object to access different URLs stored in the browser's history (the pages that have been visited recently). Properties for history include current, previous, and next, which can be used to get the URLs of recently visited pages. The length property can be used to determine the number of URLs that are stored in the history, and then the history.go(x) method can be used to go to a particular entry, where x is the number of entries to go backward in the history. (To go forward, make x a negative number.) Other methods include back() and forward(), as in the following:

<a href="" onclick="history.back()">Go back</a>

The location Object

As mentioned, the location object is actually part of the window object, so it's technically referenced using window.location. In practice, scoping generally enables you to leave off the window and just use location, as in location.href.

You can access a number of different properties of the location object, all of which are designed to help you learn different portions of the URL of the current page. For instance, location.href is used to display the entire URL of the current page:

document.write("The current URL is: " + location.href);

The rest of location's properties hold portions of the page's URL that can be accessed separately. They include the following:

href Holds the full URL
protocol Stores the protocol, as in http:
hostname Stores the name of the computer that is hosting the current document, as in http://www.fakecorp.com
port Stores the port number, if relevant
pathname Stores the path statement, including the directories, the subdirectories, and the name of the current document

You can use this information for something as simple as a command to place the current URL on every page, perhaps near the top or the bottom of the page. For instance:

document.writeln("This page's URL is: " + location.href);

You can also cause a new page to load in the browser window with a command such as this:

location.href = "http://www.fakecorp.com/newpage.html";

The document Object

The document object is another child of the window object, but it's a child that's all grown up. This one is really the main object you'll be dealing with when it comes to JavaScript, and particularly HTML forms. That's not to say other objects aren't accessible, but the document object is where all the other objects and elements on your page are stored. So it's through the document object that you'll access and alter those elements.

The document object's properties include

domain Stores the domain at which this document is located (as in http://www.fakecorp.com)
URL Stores the URL to the current document
referrer Can be used to determine the URL of the page from which this page was linked (the page that referred the user to this page)
lastModified Stores the date when the document was last changed
title Stores the title of the document (as defined between the <title> tags)
anchors This is an array, which stores each of the anchors in the document that has a name associated with it
images Another array that stores all the images on the page
forms Yet another array, designed to make different forms on the page accessible

Most of these are fairly self-explanatory. The last few arrays can be accessed using the same approach to arrays that was discussed in "Introduction to JavaScript." For instance, to find out the URL to the first image on the page, you could use this:

alert(document.images[0].src);

You could also set that image to a new URL, which would actually substitute the image on the page. This is something we'll look into more in "Adding Dynamic HTML Elements," as it's considered a "dynamic HTML" trick:

document.images[0].src = "images/new.gif"

The document object includes a few methods with which you are already familiar, such as document.writeln(), which is used to write a line of text and markup to the page. Similarly, document.write() can also be used for this purpose—the only difference is that writeln() includes a hard return at the end of each line. (Generally that isn't important in XHTML markup, unless the return occurs inside a <pre> element or inside some other element definitions. )

Another method enables you to clear out the current markup first, and then write to the page. It's the document.open() method, which clears the page. Follow it with document.write() or document.writeln() methods and the document.close() method, and you've got a new page, as shown in Listing 2.

Listing 2 Using a Form Value for Personalization

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">

<head>
<title>Personalization Page</title>
<script type="text/javascript">
<!-- Begin hiding
function personalizePage ()
{
var userName = personalForm.myName.value;
document.open()
document.write("<html><head><title>New Document</title></head>")
document.write("<body><h1>Welcome, " + userName + "</h1>")
document.write("<p>This page has been customized for your personal enjoyment.</p>")
document.write("</body></html>")
document.close()
}
// End hiding -->
</script>
</head>

<body>
<h1>Personalize the Page</h1>
<p>Enter your name, then click the Personalize button. The content of the page will change.<br /> Note that the URL will not change, only this page's content.</p>

<form name="personalForm">
Enter your name: <input type="text" name="myName"> <input type="button" name="personalButton" value="Personalize " onclick="personalizePage()">
</form>
</body>
</html>

Note that this example not only demonstrates the document.open() method, but it also demonstrates that you're not actually changing documents. The statement var userName = personalForm.myName.value; shows that the document is still the ultimate scope—it's able to access the personalForm object without a more strict object reference. If this were a new page (changed to using location.href, for instance), you'd have a tougher time accessing that form value. Figure 2 shows Listing 2 in action.

Figure 2 On the left is the original page; on the right is the page after the document.open() method has been invoked.

Previous: Understanding JavaScript Events Next: JavaScript and HTML Forms