tags:

views:

56

answers:

2

It seems that in Javascript, if you have a reference to some DOM element, and then modify the DOM by adding additional elements to document.body, your DOM reference becomes invalidated.

Consider the following code:

<html>
<head>
<script type = "text/javascript">
function work()
{
 var foo = document.getElementById("foo");
 alert(foo == document.getElementById("foo"));

 document.body.innerHTML += "<div>blah blah</div>";
 alert(foo == document.getElementById("foo"));
}

</script>
</head>

<body>
<div id = "foo" onclick='work()'>Foo</div>
</body>
</html>

When you click on the DIV, this alerts "true", and then "false." So in other words, after modifying document.body, the reference to the DIV element is no longer valid. This behavior is the same on Firefox and MSIE.

Some questions:

Why does this occur? Is this behavior specified by the ECMAScript standard, or is this a browser-specific issue?

Note: there's another question posted on stackoverflow that seems to be referring to the same issue, but neither the question nor the answers are very clear.

+1  A: 

The reference won't be valid again until the function ends and the DOM refreshes and all the innerHTML is actually converted. Try calling the function again using setInterval and you will see the first alert being true again.

Edit: I just noticed that your HTML string doesn't have an id="foo" in it. Put that in it and try again.

Robusto
+1  A: 

When you append to document.body.innerHTML, that's equivalent to

document.body.innerHTML = document.body.innerHTML + "<div>blah blah</div>";

When you assign to innerHTML like that the browser has to reparse and therefore recreate that part of the DOM. The div element in foo is still valid, but it's not a part of the document anymore. Then, of course, when you call document.getElementById it gets the new div that replaced foo.

The behavior DOM specific, so it's not defined in the ECMAScript standard. It's not defined in any current W3C standard, since innerHTML was originally a non-standard property, but it is finally standardized in HTML5.

The solution is to either call document.getElementById to get the reference back, or use document.createElement, <element>.appendChild, etc. instead of setting innerHTML.

Matthew Crumley
`innerHTML` is indeed standardized in HTML5.
Tim Down