Skip navigation


From Here to There

by Ryan Frishberg
When we used innerHTML to change the text in NN 6, it worked, but this is not the W3C recommended way. In fact, innerText, outerText, and outerHTML aren't supported by Netscape 6; Netscape only included innerHTML support to appease the overwhelming demand for it. To change content effectively with W3C compliance, we could create each little element, append text to it, etc.... For example, to put the following HTML code in another element, we'd have to do a lot of work. Here's the HTML code we want to insert:

This is <b>some bolded</b> text.

And to create that, we'd have to use:

text1 = document.createTextNode("This is ");
bTag = document.createElement("b");
textB = document.createTextNode("some bolded");
text2 = document.createTextNode(" text.");
bTag.appendChild(textB);
document.body.appendChild(text1);
document.body.appendChild(bTag);
document.body.appendChild(text2);

Wow, that sure was a lot of work for such a simple thing, which we could have just done:

document.body.innerHTML="This is <b>some bolded</b> text.";

As you can see, creating each little element can be very can become tedious and time-consuming. This is one reason why ranges are needed. A range is an area (or range) of any HTML (or XML) content. It can span across multiple tags, in between text nodes, etc.... This is major enhancement in Level 2. You can again hear about this from the "horse's mouth" in somewhat technical discussions at Document Object Model Core and Document Object Model Range, and there's a good article on ranges by Jeffrey Yates, which I recommend you read. Although we won't discuss the details of ranges as that could be a long discussion (the article by Jeffrey Yates, link above, explains about ranges), we will use it to change a layer's content. Here's the proper means of changing a layer's content (works in NS 6 but not IE 5) by W3C DOM Standard using ranges. Consider this function:

            function writeLayerNSSix(node,txtHTML){
                        var newRange = document.createRange();
                        newRange.selectNodeContents(node);
                        newRange.deleteContents();
                        var newHTML = newRange.createContextualFragment(txtHTML);
                        node.appendChild(newHTML);
            }

Let's apply it to replace the text in "span1":


     <div id="div1">
          <span id="span1">This is the text of SPAN1</span>
          This text is not in a span tag.
     </div>
     <script>
          writeLayerNSSix(document.getElementById("span1"),"Now, this is the <b>NEW</b> text for <i>SPAN1</i><b>!</b>");
     </script>

Our document now looks like:

      <div id="div1">
            <span id="span1">Now, this is the <b>NEW</b> text for <i>SPAN1</i><b>!</b></span>
            This text is not in a span tag.
      </div>

Recreate our generic writeLayer() function.

I should also note the function we created to change a layer's content (way back when we used innerHTML) is not W3C compliant, even though it does work in NS 6. To make it W3C compliant, our code is going to be a little longer. However, before we begin, we must learn a way to distinguish between browsers IE 5 and NS 6. We could use if(document.getElementById&&!document.all) and that will work, but what about IE 6? IE 6 supports document.all, and it will return false for that statement and keep on using the older "innerHTML method," when it could use the W3C compatible way, like NS 6. So, since IE 5 and IE 5.5 don't support getAttributeNode() (which we haven't discussed in this article, but you can find more information about it from W3C) for elements, we can use if(document.body.getAttributeNode), knowing the NS 6 and IE 6 support that feature and will return true for that while IE 5 and other browsers will return false for that if() statement. In light of this,
let's rewrite our function to change a layer's content:

     function writeLayer(layerID,txt){
               if(document.body.getAttributeNode){
                         node = document.getElementById(layerID);
                         var newRange = document.createRange();
                         newRange.selectNodeContents(node);
                         newRange.deleteContents();
                         var newHTML = newRange.createContextualFragment(txtHTML);
                         node.appendChild(newHTML);
               }else if(document.getElementById){
                         document.getElementById(layerID).innerHTML=txt;
               }else if(document.all){
                         document.all[layerID].innerHTML=txt;
               }else if(document.layers){
                        with(document.layers[layerID].document){
                                   open();
                                   write(txt);
                                   close();
                         }
               }
     }

Notice that we just pass the layerID, rather than the node. This is added for compliance, and I also added this line which was not included in our writeLayerNSSix() function to accomplish this:
node = document.getElementById(layerID);

Before going on, there's one other Level 2 DOM feature I wish to discuss: event listeners.

Next -->