California Ajax Solutions Team

When you point your browser to a URL by typing its address in the address bar or clicking on a hyperlink, a web server is contacted and sends the page to your browser. If the loaded page is an HTML document, the browser will build a tree from it. The HTML delivered by the server is treated as a script to build this tree. The browser will then render that page based on the tree, making it appear on the screen. In other words, the browser doesn't really use the human-readable version of a web page except for helping it build the tree initially - the tree is then the only thing it uses.

Each browser builds the tree slightly differently, but there is a great deal of commonality. Thus, there are standard methods for manipulating the tree once it is inside the browser. These ideas are part of a model developed by the W3C (World Wide Web Consortium) called the Document Object Model, or DOM. The model consists of properties and methods (in Object Oriented Programming terms) for accessing the tree, which is done in the client-side language JavaScript.

For a static web page, this sort of thing isn't terribly useful. You just look at it, and then move on to something else. For a dynamic (interactive) web page - one that functions as an application - the ability to manipulate the DOM tree is almost always necessary to perform any useful work.

There are standard methods for manipulating the tree, but a good deal of this work involves creating new elements and adding them to the tree in appropriate places, or else deleting elements. Elements correspond to the tags you see when you look at the HTML version of the web page. So a table consists of a table element, usually with a child called a tbody, which in turn has a child element for each row in the table, and so on. I chose this example to point out one of the ways manipulating the DOM differs from specifying something in HTML. In HTML, almost no one really specifies the tbody node. If the browser requires one, it will create it on-the-fly when it sees a <table> tag. But if you are creating a table dynamically using DOM functions, you should include the tbody node for browser portability.

Here's a relatively trivial examine of how DOM manipulation would be used. If you had a truly bilingual web site, it would make sense to just write web pages in both languages. But suppose you just wanted to have a small part of a page be in either English or Spanish. You could simply do the following:

1. Create a DIV node to display the text.

2. On load, call a function to create English and Spanish paragraph nodes in JavaScript

3. Have the default language paragraph appended to the DIV node.

4. Provide a button or some other mechanism to switch languages. When the user selects a new language, remove the paragraph child from the DIV node, and append the appropriate new paragraph node in its place. You don't get rid of it, you just remove it from the tree.

When you do this, the screen will change instantly, since any changes to the DOM tree are immediately rendered by the browser.

A more interesting application of DOM manipulation is to change the tree in response to user choices (other than simply clicking a button). For example, a form can be fairly complex, with the various parts of the form dependent on what the user has already done. We give a fairly straightforward example of this in the Ajax overview article, where you choose a brand of automobile and then are presented with a list of models based on which brand was selected.

Another technique we like is to have what appear to be multi-page forms, so the user can page through the form in both directions. A form can be so complex that it becomes overwhelming when displayed on a single page. But if you break it up into multiple pages, it becomes clearer. If you have filled out any customer satisfaction surveys on line, you have probably seen this technique in use. You answer a few questions, click Next, and move on through the survey. You can go back if you want to change an answer.

A form cannot, however, span multiple web pages. Since it a child of a web page body (or one of the body's children), it must be entirely contained within a page. The simplest way to work around this problem is to stay on the same page and change what the user sees at any given time. This has a beneficial side-effect: there are no page loads required, so you never have to wait for the server. All of the code to display all of the parts of the form is available at the initial load (although there are workarounds for this as well). To allow the user to page backwards and forwards through the form, you simply need to remember all the previous answers so as to make them "sticky." When you display any given part of the form, you just initialize it with the known value if there is one. Otherwise, it's just blank. When you get to the end of the form and are ready to send it to the server, you just utilize all the known "saved" answers from all the display sections. We generally build an XML string for this, but there are other choices.

Since the DOM tree controls what appears on the screen at any given time, you manipulate the tree to show whatever part of the form you want to see on page load and in response to the user clicking on Next. This brings up the other very common aspect of DOM manipulation - event listeners. An event listener is a function that is called in response to an event caused by the user doing something. So when the Next or Back button is clicked on, the onClick event fires and the handler associated with that button is invoked. In our paging system, this causes the display to change to a different part of the form, and usually causes all the values specified in the current part of the form to be saved.

An alternative approach is to associate event listeners with each input element (drop-down lists, text boxes, radio buttons, etc.) in the form. Depending on the element type, you will probably have to choose the most appropriate event. For a drop-down list, you probably only want to note when the current selection changes, so you would specify an onChange listener. For a checkbox or a radio button, you must specify an onClick listener, since Internet Explorer does not support onChange for these input types. When the user changes the value of any input, the event handler takes care of saving the new value, so you don't need to do it when you change the display. There's a bonus here - you can perform validation at this time. Many users are annoyed to be informed that their choice was no good after-the-fact. And doing so on form submission is even worse. The best solution is to validate input immediately, especially if the choice will affect subsequent actions.

There's more to the DOM than adding element nodes, deleting them, and making good use of event listener functions. But if you master the use of these techniques, you are well on the way to being an effective Ajax developer.