slayeroffice - web experiments gone horribly awry

02.03.2006 - Alternatives to innerHTML

Intended as an introduction to those looking to move beyond innerHTML to DOM methods, I give you Alternatives to innerHMTL.

I'm not trying to push anyone one way or the other in this article and my intention is not to start a debate over it, at least not here...I'll reserve convincing you to come to the DOM Side of the Force™ for when and if we meet in person (SXSW anyone?).

I hope the article proves of some interest and use to you, and please hit me up with any suggestions, corrections or additional examples you'd like to see.

Nice work that man. A few thoughts:

The quick cloneNode approach to emptying an element's content is neat, but it will invalidate any object references you have to the element. In your example, you're explicitly looking up the element in the call [so_clearInnerHTML(document.getElementById("mContainer"));] but if you were just calling so_clearInnerHTML(myobj) then myobj will point to an element in limbo when you finish the call. Might warrant a warning or something, that.

When IE creates a malformed DOM tree based on malformed HTML, does cloneNode() break stuff?

Is documentFragment useful? If you want to insert 10000 LIs into a new list, say, then doing

document.body.appendChild(ul);

for (i=0;i<10000;i++) { ul.appendChild(li); }

is indeed slow. However,

for (i=0;i<10000;i++) { ul.appendChild(li); }

document.body.appendChild(ul);

is a lot faster because you only update the document at the end. Is documentFragment only useful when you don't have a parent element to put everything in (which essentially acts as a documentFragment)?

What's wrong with

dce = document.createElement;

rather than creating a wrapper function?

I do occasionally think about writing an HTML parser for JS which would do the innerHTML stuff itself. It'd be horrendously slow, mind.

Great article, in case I didn't say; it should be useful for lots of people!
Posted by Stuart Langridge on February 3, 2006 @ 7:41 pm


Thanks for the feedback, Stuart. I've added your caveat for the cloneNode method to the article.

>>When IE creates a malformed DOM tree based on malformed HTML, does cloneNode() break stuff?

I hadn't considered it...may have to experiment with that.

>> Is documentFragment only useful when you don't have a parent element to put everything in (which essentially acts as a documentFragment)?

Precisely. If the parent you are appending to already exists in the DOM, you cant append to it without slowing everything down to a crawl. Using a fragment solves that problem without having to create nodes you dont want or need.

>> What's wrong with dce = document.createElement;

Nothing :) Just never occured to me to do it that way.

>> I do occasionally think about writing an HTML parser for JS which would do the innerHTML stuff itself. It'd be horrendously slow, mind.

Likewise - I've started and stopped work on one at least 5 times.

>> Great article, in case I didn't say; it should be useful for lots of people!

Thanks! I appreciate it.
Posted by Steve on February 3, 2006 @ 8:42 pm


Again... great stuff. This will definately be a nice resource for learning about the differences of the two methods.

Quck correction for you... the function names in example 2[b] are inconsistant.

The function is named "getTextNodes", but then the recursive reference is "so_getText". And to finish it off (or start it actually) the call to run the function in the first place calls "grabTextNodes".

All great names... just pick one =)
Posted by Aaron Barker on February 3, 2006 @ 8:48 pm


lol, thanks Aaron. fixed :)
Posted by Steve on February 3, 2006 @ 8:53 pm
Really nice article, *bookmarked*! :-)

A minor thing though (only due to the above mentioned): missing a closing parentheses in example 4a - which I btw. think should be just 4.
Posted by Allan Rasmussen on February 7, 2006 @ 5:29 am


Thanks Allan - fixed.
Posted by Steve on February 7, 2006 @ 2:36 pm
In example 4 the innerHTML method results in the mContainer node having the same children as the hiddenContent node. But in the dom version the only child of the mContainer node is the copy of the hiddenContent node. And under that are the children you actually wanted to append. At a glance I don't see a way around it that doesn't involve appending the children of hiddenContent one by one or moving them to a documentFragment one by one before appending that. This may or may not be a big deal depending on your requirements. But it should be noted I think.
Posted by Marco on February 9, 2006 @ 2:37 am
Thanks for this great article.

I think I spotted a little mistake in example [2b]:

while(obj.childNodes[i]) {

txt[txt.length] = so_getText(obj.childNodes[i]);

i++;

}

Shouldn't txt[txt.length] be txt[i]?
Posted by Kristof on February 10, 2006 @ 11:54 am


@Marco: Excellent point, I've added a note to the example that says as much.

@Kristof: "i" would probably work as well, but since its in reference to the childNode collection I wanted to stick with the current length of the array to avoid accidentally overwriting something in the array.
Posted by Steve on February 10, 2006 @ 8:46 pm


Hi Steve

Now I understand it. I must have had a very bad day that I didn't see the logic of txt[txt.length] when I wrote my first comment here :)
Posted by Kristof on February 20, 2006 @ 7:31 am


In a effort to see just how much faster is innerHTML method, I wrote a very simple page. The result is interesting. DOM object method is actually FASTER at least in this case.

--------------------------------------------------------------------------

<html>

<head>

<title>test</title>

<META HTTP-EQUIV="Expires" CONTENT="-1">

<meta http-equiv="Cache-Control" CONTENT="no-cache">

<META HTTP-EQUIV="Pragma" CONTENT="no-cache">

</head>

<body >

<a href="javascript:void(0)" onclick="javascript:click1()">test1</a>

<a href="javascript:void(0)" onclick="javascript:click2()">test2</a>

<script type="text/javascript">

var top=20;

var left=25;

var left2=620;

function click1(){

top=20;

for(var i=0;i<200; i++)

{

document.body.innerHTML+="<div style='height:30;width:30;position:absolute;top:"+top+";left:"+left+";background-color:red;'>inh</div>";

left+=40;

if(left>600)

{

left=25;

top+=40;

}

}

}

function click2(){

top=20;

for(var i=0;i<300; i++)

{

var a = document.createElement('div');

a.style.height="30";

a.style.width="30";

a.style.position='absolute';

a.style.top = top;

a.style.left = left2;

a.style.backgroundColor="blue";

document.body.appendChild(a);

a.appendChild(document.createTextNode("dom"));

left2+=40;

if(left2>1220)

{

left2=620;

top+=40;

}

}

}

</script>

</body>

</html>
Posted by Zhaozhi on March 30, 2006 @ 4:13 pm


Comments have been closed for this post.