[OBSOLETE] Please use the JQuery library to achieve cross-browser DOM manipulation (and more!)
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.
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:
| +-+ title
| +-- "Hello World!"
+-+ h1 (id=hello)
| +-- "Hello "
| +-+ i
| +-- "World"
+-+ p (id=goodbye, align=right)
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
- 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.
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.
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.
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.
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.
Other than the childNodes property you’ve seen previously, all nodes also contain a firstChild property to allow you to access childNodes 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.
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
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.
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”.
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.
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.
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.
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.
[TBC – this is going to be a very long article, might organize it into pages]
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.
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"));
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.