Ben
Ben

Reputation: 57217

JS: innerHTML and DOM aren't cooperating

I've noticed a funny behavior and was wondering if anybody could shed some light on the reason.

It breaks down like this:

Here's a sample script:

var D = document.createElement("DIV"), B = document.createElement("BUTTON");
B.innerHTML = "Is it true?";
document.body.appendChild(D);
D.appendChild(B);

B.onclick = function() { alert("Elvis Lives!"); }

At this point, it works fine. Then, add this line:...

D.innerHTML += "What about Tupac?"; 

...and the button breaks. So, I'm just using appendChild for all elements now.

But -

Upvotes: 2

Views: 564

Answers (3)

mplungjan
mplungjan

Reputation: 177885

Not an answer, just a test page - looks very strange - I can confirm your findings

<script>
window.onload=function() {
  var D = document.createElement("DIV"), B = document.createElement("BUTTON");
  D.id = "div1"
  B.innerHTML = "Is it true?";
  B.onclick = function() { alert("Elvis Lives!"); }
  D.appendChild(B);
  document.body.appendChild(D);
}
</script>
<a href="" onclick="document.getElementById('div1').innerHTML += 'What about Tupac?'; return false">Click</a><br>
<a href="" onclick="alert(document.getElementsByTagName('button')[0].onclick); return false">Test</a>

update: Lessons learned - be consistent.

This works as expected

<script>
window.onload=function() {
  var D = document.createElement("DIV");
  D.id = "div1"
  D.innerHTML = '<button onclick="alert(\'Elvis Lives!\')">Elvis</button>'
  document.body.appendChild(D);
}
</script>
<a href="" onclick="document.getElementById('div1').innerHTML += 'What about Tupac?'; return false">Click</a><br>

Upvotes: 1

Anurag
Anurag

Reputation: 141879

innerHTML is a shortcut for creating DOM elements. When you append something to the outer div using innerHTML, this is what happens:

D.innerHTML += "What about Tupac?";

which is the same as,

D.innerHTML = D.innerHTML + "What about Tupac?";

which is the same as,

D.innerHTML = "<button>Is it true?</button>" + "What about Tupac?";

which finally becomes this,

D.innerHTML = "<button>Is it true?</button>What about Tupac?";

Now in the last step, we completely replaced the existing contents of the div, with a new string which contains HTML. As far as the DOM is concerned, it doesn't care whether a user typed the HTML by hand, or it came from calling innerHTML on a DOM node. All it cares about is, is that it has a string of HTML, which must be converted to a DOM. A new button element is created at this time, which is why the onclick stops working - it's not the same element anymore.

Upvotes: 3

lincolnk
lincolnk

Reputation: 11238

(this is a lot of educated guessing) I think when you modify D's innerHTML, the dom within D is destroyed and created from the new value. So when the new contents are constructed, you are getting a brand new button, which is not the same node as B. since you set the onclick handler via js and not by an attribute on the original element, the new button does not have that function reference. however B still works as can be demonstrated by calling

B.click();

after you append to innerHTML.

to prevent the thrashing of the dom within D, you can do this instead of using innerHTML:

D.appendChild(document.createTextNode("What about Tupac?"));

Upvotes: 4

Related Questions