[OBSOLETE] Please use the JQuery library to achieve cross-browser DOM manipulation (and more!)
The DOM (Document Object Model) allows us to represent a HTML page as a tree-like structure. With the increased use of Javascript and new concepts such as AJAX, DOM has become a rather important model. Without good knowledge of the DOM, you may find yourself in a fix when trying to even manipulate the simplest elements.
I assume you have intermediate knowledge of HTML and Javascript, for they are essential in manipulating the DOM. Simple knowledegde of XML may also help, since DOM is actually a method for processing XML. This tutorial does not compare between DOM and SAX, but simply focuses on DOM. This tutorial is not meant to solve a particular problem, but to increase your knowledge of the DOM so that you can work with it better. If you don’t have these prerequisites I suggest you brush up your skills before coming back, or just treat this as a bedtime story.
The methods here have been tested in Internet Explorer and Mozilla Firefox. Despite browsers having their own “extensions” to DOM and Javascript, they attempt to comply with the World Wide Web Consortium (W3C) DOM standard. By using methods belonging to the standard, you can omit ugly browser detection code. It is still recommended that you test the scripts in your target environment to see if the browser supports these features. Do feedback if there is a simple and better cross-browser method.
Jump to a specific topic:
- The HTML Page
- Essential DOM Method: getElementById()
- DOM Debugging
- Common Attributes and Methods
- Common Styles
- Form Manipulation
- Table Manipulation
The HTML Page
We start by first examining a HTML page.
Hello World!
Hello World
Goodbye!
So what can we see from this simple page? When the page is parsed into a DOM tree, it will have a hierarchy like this:
+ html
|
+-+ head
| |
| +-+ title
| |
| +-- "Hello World!"
|
+-+ body
|
+-+ h1 (id=hello)
| |
| +-- "Hello "
| |
| +-+ i
| |
| +-- "World"
|
+-+ p (id=goodbye, align=right)
|
+-- "Goodbye!"
We introduce a few DOM terms here. Every item you see on that tree is known as a Node. There are 2 types of nodes, Text Node and Element Node.
Text nodes contains text literals, just like those strings above in quotes. They are the innermost nodes and cannot contain other nodes nor formatting. (if the text has formatting it would have been in another element node such as ).
Element Nodes represent each tag you place in angle brackets <>
. Each element node has
- a type – which is its tag name, e.g. a
node or a
node.
- subelements – are all nodes written within its tag, e.g. the
node contains 2 subelements, the “Hello ” text node and the
element node, which in turn contains 1 subelement which is the “World” text node. Note that nodes may have zero sub-elements. In the DOM world subelements are known as Child Nodes.
- attributes – are properties of the node that describe the node itself, usually written within the start tag. For example, the
- methods – allow you to perform an action on the node object. For example, you may use table.insertRow() to create a new row, or use table.getChildNodes() to access the sub elements within the node.
- style – is actually an attribute of the node, but it has been specially discussed because it is very common to adjust the look of an element using its style, and also its relation to cascading style sheets (CSS). In fact, the CSS style of the node can be reflected through this property.
-
Once you understand the structure of the DOM tree, we’ll start to explore how you can use Javascript to access and manipulate the DOM, as well as common attributes, methods and styles. We’ll also focus on form elements, which are common targets of DOM manipulation.
Essential DOM Method: getElementById()
To start working with DOM you need to to first obtain a reference to one of the nodes. One method is to navigate through the tree from the root to your desired node, but it is often tedious since most HTML files we work with are mostly generated and many times larger than the example above.
Therefore the most common method is to label your node with an ID, and use the getElementById method to locate your node.
The document variable is a global Javascript variable that gives you access to the HTML document. Here we locate the node with the ID “hello”, and store it inside the helloNode variable. If we run this script within the HTML file we created above, this node represents the
node with the word “Hello “, and a child node
. We prove this by inspecting the node.
From this sample we learn a few properties that are common to most element nodes. The nodeName property tells you what kind of tag it is (which you should already know). Each element node also has a childNodes array, which contains all its sub elements. Using the length property of the childNodes array you can drill into the node using a loop or otherwise.
DOM Debugging
A side note about DOM programming is the use of the alert command to quickly debug your code, as shown in the previous example. Using alert like above allows you to inspect your variables to make sure they contain values they should contain, or what the value is if it’s wrong. Also since Javascript will run your code until it hits an error, I often use the alert to check which piece of code has been run. For example:
When run, this code meets with an error before the alert. After I shift the alert one line up and re-run the code, the alert appears before the error occurs. This allows me to zoom into the offending line. You may argue that using a browser such as FF’s Javascript Console directly shows the offending line without the use of an alert. That is true, but when writing cross-browser code, the script might run fine in FF, but encounters an error in IE. In that case you’ll be stuck a misleading line number, or Line 0… This approach works irregardless of the browser you are testing on.
The alert method “fails” under some circumstances, especially in big loops and timer events. I often go into a big loop or a repeat timer event with the alert popping up everytime I close it, forcing me to crash the browser. When debugging such code I use an alternative, which involves setting up a display on the page.
Supposedly a timer event continuously add/removes items from the helloNode. If using an alert, you be stuck with the alerts repeatedly popping up. But using this method, the value is fed into a text box (I usually place it at the top of the page). If you place the inspection code right after the code where you change the node inside the timer, you get a “real-time” value of the length of the node. You can use a similar concept and modify the “debug” element into a
, depending on your need to append instead of overwrite values.
Common Attributes and Methods
All element nodes will contain the following properties and methods as part of the World Wide Web Consortium (W3C) DOM standard. The variable name elem used here represents an element node.
Attributes
Use elem.getAttribute(name) to obtain the value of an element attribute, and elem.setAttribute(name, value) to set the value of an attribute. Note that an element can only have one value for an attribute, so if the setAttribute is called over an existing attribute name, the value will be overwritten. If necessary, the elem.attributes contains a list of all attributes so that you can enumerate it.
However, the attributes of the element are usually exposed as properties of the object, for example:
The preferred approach is to use the property directly, and use the setAttribute method only when the attribute you want to set cannot be determined until runtime, and is stored in a string.
Relative Nodes
Other than the childNodes property you’ve seen previously, all nodes also contain a firstChild property to allow you to access childNodes[0] directly, either when you want the first item only, or when you’re sure there is only one item. elem.nextSibling returns you the next element that has the same parent as the current element, and elem.parentNode returns you the parent of this element.
Creating/Removing Elements
So far most methods you’ve seen allow you to traverse and inspect the DOM, but little modifications. The following example will open your eyes to what DOM can actually do to turn a HTML page upside down!
Try run this snippet with the original HTML. Hey! Where did my “Hello World” go? It now says “Hello HELL”… What you’ve just did is removed the 2nd child node from H1, which consists of “World
“, added a “” tag to the end of
and put the words hell inside the newly created tag. The resulting relevant HTML source looks something like
Hello HELL
Hello HELL
However, this cannot be seen when you view the source; it still shows the original “Hello World”. To explain the code, document.createElement allows you create arbitrary tags and elem.appendChild allows you to add these elements to it. Use elem.insertBefore if you need to insert elements instead of adding them to the end. document.createTextNode allows you to create a new text node to be added to the page. All these methods return the node that was created or appended, so that you can continue to work with it.
From this example you should be able to understand that you can now take ANY node in the DOM, transform it in ANY way by adding, removing and modifying the elements and end up with a possibly radically different page.
This is the power of the DOM.
Common Styles
The style of an object can be set in 2 ways. The first way is by using CSS, which includes inline, internal and external style sheets. The discussion of CSS is beyond the scope of this tutorial, but be aware of style precedence. The second way is by using the DOM with Javascript. The style of an element can be accessed by elem.style. The sub-elements of the style object control the style of the element and can be get/set. Read on to find out how they are used.
Visibility
Every element may be visible or hidden. An element can be hidden in two ways: by setting elem.style.display to “none”, or elem.style.visibility to “hidden”. The difference between the two is that setting visibility hides the element but it still takes up the space in its position. Setting display to none will hide the element completely. Depending on your need you’ll choose one or the other. The example below illustrates the difference.
The table border is purposely shown to show you that the button still takes up space when the visibility has been set to hidden. [screenshot?] To re-display the elements, set the visibility to “visible”, or display to “inline”.
Positioning
DOM also allows you to position elements at absolute positions on the screen, possibly stacking one over another. To do so, set the elem.style.position to absolute, then use the elem.style.top and elem.style.left styles to position the element.
Combining this positioning effect with timers you achieve dynamic animation of elements. That is how floating snowflakes and sliding menus are created.
Borders
Using HTML, you could only specify entire borders. With CSS, you could control borders of individual cells, and even the left or right border only. Now with DOM and Javascript, you can change the borders on the fly without a page refresh. Borders are usually applied on table cells and layers.
Note that the DOM style property is named “borderRightWidth”, while the CSS property is name “border-right-width”. This is the general naming difference between CSS dashed-names and DOM camel-cased names. If your first guess isn’t correct, check the reference.
Class
If you’re familiar with CSS, by now you should realize that changing the style of elements through DOM is the same as setting the style using CSS, but you now have the power of doing it dynamically after the page is displayed. If you need to set a number of styles with a single action, you can combine CSS into this by defining the target style, and setting the elem.className property of the element.
Form Manipulation
Forms have unique attributes only found in form objects. For example, most form components contain a value property which represents the value that will be sent to the server when the form is submitted. In the DOM debugging section of this article you were already shown an example of how to access the value property of a text input object.
Checkboxes and Radio buttons have an additional checked attribute which indicates if they are currently selected. Select objects have a options child property which holds all option objects for the select. You may add/remove options dynamically by manipulating that property.
textarea
submit/reset/button
[TBC – this is going to be a very long article, might organize it into pages]
Table Manipulation
Manipulation of tables usually involves traversing an existing table, or adding/removing rows to it. Although you can also “create” tables on the fly by document.createElement(“table”), it is not common.
One way to add/remove rows is to apply what you have learnt previously, by using createElement(“tr”) and then use appendChild() to add to the table. However, the table object provide methods for easier manipulation of rows and cells.
No.
Name
Phone
Now this is a rather big chunk of complicated code, we’ll go through it slowly. It is best you run this example to see the results. First, we create a HTML table of 3 columns containing only the header row. We’ll use the buttons Add and Remove to put people into the table.
The add function retrieves the table node, and calls insertRow on the table. This method inserts a new row at the specified position; if you put 0 as the argument, it’ll go into the first row, and 1 will be the second row. -1 inserts it at the end of the table. It conveniently returns the newly created row, so we continue to use it to insert cells. The insertCell method works the same way, adding a cell to the end and returning the new cell. Since we just want a text node inside, we call appendChild directly to add the text node. If you need more complicated elements inside, save the cell as a variable, as below:
var td = tr.insertCell(-1);
td.className = "aStyle";
var b = td.appendChild(document.createElement("b"));
b.appendChild(document.createTextNode("1234567"));
The remove function simply removes the 2nd row from the table (index 1). It adds a check to ensure there is more than 1 row when the remove is called, to prevent an error when there’s nothing to remove, as well as to demonstrate the rows collection of the table element. Similarly, a tr element contains a cells collection which you can use to traverse the cells in a row.
One thought to “DOM using Javascript”