innerHTML and tables...

R

RobG

I know you aren't supposed to use innerHTML to mess with table
structure, but it seems you can't use it just after a table without
damaging the containing element.

I added a table to a div using createElement methods, then added a bit
of extra text using innerHTML, only to find most of the attributes
removed from the table.

Below is a script that calls the same code to add a table inside a
div. It adds an onclick to the div and change the style. When it is
called without an extra bit of innerHTML, all is fine. But if
innerHTML is also used, the background-color is removed as is the onclick.

I know there's no spec for innerHTML, but the above behaviour happens
on IE & Firefox Windows as well as Firefox & Safari Mac.

It doesn't seem to happen if a div is used instead of a table. Is
this a known effect of innerHTML?



<script type="text/javascript">

function addDiv ( el, b ) {
var oT = document.createElement( 'table' );
var oTb = document.createElement( 'tbody' );
var oTr = document.createElement( 'tr' );
var oTd = document.createElement( 'td' );
oTd.appendChild( document.createTextNode( 'text added to table' ) );
oTd.style.backgroundColor = '#ddddff';
oTr.appendChild( oTd );
oTb.appendChild( oTr );
oT.appendChild( oTb );
oT.onclick = sayHi;
el.appendChild( oT );
if ( b ) el.innerHTML += 'Here\'s some more text';
}

function sayHi(){
alert( 'Hi from ' + this.nodeName );
}

</script>

<div onclick="addDiv( this, false );">click me 1</div>
<div onclick="addDiv( this, true );">click me 2</div>
 
V

VK

RobG said:
I know you aren't supposed to use innerHTML to mess with table
structure, but it seems you can't use it just after a table without
damaging the containing element.

I added a table to a div using createElement methods, then added a bit
of extra text using innerHTML, only to find most of the attributes
removed from the table.

I guess that the removed attributes are JavaScript functions and
listeners.

Change you "extra text" block to this:

if (b) {
var txt = document.createElement('SPAN');
txt.innerHTML = 'Here\'s some more text';
el.appendChild(txt);
}

and it will work again. Somewhere there was a link about JavaScript
inserted as a text stream. It doesn't get parsed in such case.
And your instruction DOMNode+text transforms it into text stream. Just
a wild guess but seems to be true.
 
C

Csaba Gabor

RobG said:
oT.onclick = sayHi;
if ( b ) el.innerHTML += 'Here\'s some more text';

When you do that el.innerHTML += ...
you are not (just) adding to el, you are completely redefining it.
That is, el.innerHTML += ... means:
el.innerHTML = el.innerHTML + ...
and if some property is not sitting in the innerHTML, when you redefine
it (that is, a property of el or any of its sub elements), by means of
setting its innerHTML), it's gone.

To that end, it may be instructive to actually see what that innerHTML
is. Redefine your oT.onclick like so:

oT.onclick = function(el) {return function() {
alert('Hi from ' + this.nodeName + "\n" + el.innerHTML); } } (el);

Good luck,
Csaba Gabor from Vienna
 
C

Csaba Gabor

VK said:
and it will work again. Somewhere there was a link about JavaScript
inserted as a text stream. It doesn't get parsed in such case.

On IE 6, the following will be injected and parsed. However, IE will
then claim that: Internet Explorer cannot open the Internet site ...
Operation aborted (ed: dummy, you've already loaded it) and unload it
in front of your eyes.

<body>
<script type='text/javascript'>
function scriptInjector() {
myscript = document.createElement('script');
myscript.type = 'text/javascript';
document.documentElement.appendChild(myscript);
myscript.text =
"alert('script has been parsed injected and parsed');"
}
scriptInjector();
</script>
</body>


However, take out the scriptInjector() call and change the <body> to
<body onload="scriptInjector()"> as below, and the script works just
fine for me on my Win XP Pro system:

<body onload="scriptInjector()">
<script type='text/javascript'>
function scriptInjector() {
myscript = document.createElement('script');
myscript.type = 'text/javascript';
document.documentElement.appendChild(myscript);
myscript.text =
"alert('script has been parsed injected and parsed');"
}
</script>
</body>


With Firefox, version Deer Park Alpha 1 both versions work without
error.
Go figure,
Csaba Gabor from Vienna
 
R

RobG

Csaba said:
When you do that el.innerHTML += ...
you are not (just) adding to el, you are completely redefining it.
That is, el.innerHTML += ... means:
el.innerHTML = el.innerHTML + ...
and if some property is not sitting in the innerHTML, when you redefine
it (that is, a property of el or any of its sub elements), by means of
setting its innerHTML), it's gone.

To that end, it may be instructive to actually see what that innerHTML
is. Redefine your oT.onclick like so:

oT.onclick = function(el) {return function() {
alert('Hi from ' + this.nodeName + "\n" + el.innerHTML); } } (el);

It appears to be that when you add an onclick event to any element using
DOM, it is not added to its innerHTML. When you modify the innerHTML of
the element's parent, the element is written out again, without the
onclick attribute (this seems to be consistent for any intrinsic event)
effectively removing it.

While I originally thought it only happened with tables, with further
testing it appears that the same thing happens with other elements too -
intrinsic events are not included in the innerHTML if they aren't in the
original HTML source and have been added using some other method.

It does not seem to happen with other element attributes - style, id,
name, etc. nor does it happen if you modify the innerHTML of the element
itself, nor if you add the event using innerHTML (I guess that's
obvious, but...).

It's just a gotcha with innerHTML that I was not aware of before.

I can only guess that dynamically attached events are not included in an
elements' innerHTML because they may be added using a number of methods
and that some may be anonymous functions. But in that case I would have
thought that the function body would become the onclick attribute:

script: oT.onclick = function() { alert('hi'); };

==> innerHTML: ... onclick="alert('hi');" ...


and so on. Is this why the W3C has not added an innerHTML-type method
to the DOM?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,772
Messages
2,569,591
Members
45,101
Latest member
MarcusSkea
Top