Castle and Riders

How To Replace innerHTML with DOM methods

JavaScript’s innerHTML method is a handy way to grab or update text from any element within your HTML document. Here’s how it works:

// set the text
var welcome = document.getElementById("hello");
welcome.innerHTML = "Howdy!";

// get the text
alert(welcome.innerHTML); // displays "Howdy!"

It’s simple to use, works great in every modern browser, and even has good backward compatibility with older browsers. There’s just one little problem: innerHTML is not a W3C standard.

Enter the DOM

To maintain standards-compliance in your JavaScript code, you need to use Document Object Model (DOM) methods to access text nodes within your HTML document. Here are some of the attributes and methods you can use (for a complete list, check out the tutorial on the “How to Create” site):

  • parent.firstChild - returns the first element under the “parent” node
  • parent.hasChildNodes() - returns true if the “parent” node has any children
  • node.nodeValue - returns the value of the node (if it is a text node or attribute)
  • createTextNode(”the text”) - creates new text you can add to your document
  • appendChild(parent) - inserts a node into the DOM tree under a parent node
  • replaceChild(newNode, oldNode) - replaces the old node with new

Unfortunately, with all this talk of “nodes” and “DOM trees,” using these methods is not quite as straightforward as innerHTML. The key is to think of the text you want to manipulate as just another element within your HTML document. Using getElementById() and these methods, you can target and modify specific text elements within the page.

Get Text with DOM Methods

Let’s start with a simple example. Let’s say I have a <div> with some text somewhere on my page:

<div id="hello">Hello World</div>

If I want to grab that text and display it in an alert, I can do this:

<script>
var welcome = document.getElementById("hello");
alert(welcome.firstChild.nodeValue); // displays "Hello World"
</script>

Notice how I have to specify firstChild.nodeValue to get at the text? Unlike innerHTML, which indiscriminately grabs whatever is between <div> and </div>, these DOM methods don’t assume the content is always text (it could be other HTML elements, for example). The child element is considered just another node in the tree, which in this case happens to be text.

However, what if my <div> is empty? This presents a problems, because it means the node I’m looking for doesn’t actually exist! This example will error out because it can’t find the “firstChild” node:

<div id="hello"></div>

<script>
var welcome = document.getElementById("hello");
alert(welcome.firstChild.nodeValue); // ERROR!
</script>

The solution is to check whether your element has any children before accessing it:

if (welcome.hasChildNodes()) {
    alert(welcome.firstChild.nodeValue);
}

Update Text with DOM Methods

Okay, so I can get text from my HTML document, but how do I change it on the fly? Changing text is a two-part operation:

  1. Create a new text node
  2. Replace the current text node with the new text node

Here’s an example:

<div id="hello">Hello World</div>

<script>
var newText = document.createTextNode("Howdy!");
var welcome = document.getElementById("hello");
welcome.replaceChild(newText, welcome.firstChild);
</script>

Let’s step through it: First I start with a <div> containing my original “Hello World” text that I want to replace. Next I call createTextNode() with my new “Howdy!” message. At this point the text node is floating somewhere in DOM-space and I need to attach it to something, so I target the <div> using getElementById(). Finally, I call replaceChild() to swap the old text with the new text.

I can simplify this a little by merging the call to createTextNode() into the replaceChild() method, like so:

var welcome = document.getElementById("hello");
welcome.replaceChild(document.createTextNode("Howdy!"), welcome.firstChild);

Another Gotcha

Once again, empty nodes create problems. The replaceChild() method works just fine if the target element already contains text, but it will error out if the element is empty. We can solve this by adding the text node using appendChild() if it doesn’t exist. As before, hasChildNodes() comes to our rescue:

var welcome = document.getElementById("hello");
if (welcome.hasChildNodes()) {
    welcome.replaceChild(document.createTextNode("Howdy!"), welcome.firstChild);
} else {
    welcome.appendChild(document.createTextNode("Howdy!"));
}

In other words, if the <div> is not empty, replace the old text node with a new one, otherwise append a new text node.

I hope this gives you a little more insight into manipulating text in the DOM — without resorting to innerHTML.

Posted on October 9th, 2007 in the JavaScript category | Permalink
You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

Leave a Reply

You must be logged in to post a comment.