help with DOM row/cell with innerHTML

N

necromonger

Hi,

I've got this code that creates a new new row and cell. I then put some
text into the cell with innerHTML - works beautifully with Firefox but
fails with IE. I guess IE doesn't support this way of doing it, but is
there another way of doing it with DOM?

newr = document.createElement('tr');

stbl.appendChild(newr);
newc = document.createElement('td');

newr.appendChild(newc);
newr.cells[0].innerHTML = (nr+1)+". "+sa[ti][nr + 1]+"<br><hr>";
(works in firefox but fails in IE 6+ too...)
 
R

RobG

necromonger said:
Hi,

I've got this code that creates a new new row and cell. I then put some
text into the cell with innerHTML - works beautifully with Firefox but
fails with IE. I guess IE doesn't support this way of doing it, but is
there another way of doing it with DOM?

newr = document.createElement('tr');

stbl.appendChild(newr);
newc = document.createElement('td');

newr.appendChild(newc);
newr.cells[0].innerHTML = (nr+1)+". "+sa[ti][nr + 1]+"<br><hr>";
(works in firefox but fails in IE 6+ too...)

I have noticed in the past that sometimes you can't access
an element in IE until it is actually added to the document.
Try writing your new row to the document (insert it in the
table), then modify the innerHTML.

Alternatively, create a text node and append your text to
it, then append it to the cell. I'm not sure, but you
should be able to create and append the HR the same way. I
don't have time to play with this myself right now, just
hoping to help out.

Rob
 
N

necromonger

Thanks ROb. You've mentioned I should "insert" the row into the table,
how do I do that? isnt appendChild doing it already (internally?)

It's good you mentioend that, because I also noticed that even when I
insert a new tr, when i check the table.rows.length, it remains the same
as before.. any ideas will help.. am very new to this (in fact today is
the 3rd day of my learning)

thanks plenty!

necromonger said:
Hi,

I've got this code that creates a new new row and cell. I then put
some text into the cell with innerHTML - works beautifully with
Firefox but
fails with IE. I guess IE doesn't support this way of doing it, but is
there another way of doing it with DOM?

newr = document.createElement('tr');

stbl.appendChild(newr);
newc = document.createElement('td');

newr.appendChild(newc);
newr.cells[0].innerHTML = (nr+1)+". "+sa[ti][nr + 1]+"<br><hr>";
(works in firefox but fails in IE 6+ too...)


I have noticed in the past that sometimes you can't access an element in
IE until it is actually added to the document. Try writing your new row
to the document (insert it in the table), then modify the innerHTML.

Alternatively, create a text node and append your text to it, then
append it to the cell. I'm not sure, but you should be able to create
and append the HR the same way. I don't have time to play with this
myself right now, just hoping to help out.

Rob
 
R

RobG

necromonger said:
Thanks ROb. You've mentioned I should "insert" the row into the table,
how do I do that? isnt appendChild doing it already (internally?)

Yes, you already do it. I was trying to think of a more
explicit way of doing it but can't think of one. I tried
creating P and text nodes and adding them rather than using
innnerHTML, changing the order, etc. but nothing seems to
work.
It's good you mentioend that, because I also noticed that even when I
insert a new tr, when i check the table.rows.length, it remains the same
as before.. any ideas will help.. am very new to this (in fact today is
the 3rd day of my learning)

I've added a "showDOM" function below. It shows that in IE
the extra stuff is added but just doesn't get
displayed(???)

I've created a new function based on insertBefore and
nextSibling, but you need an exsiting row to use it - see
if it solves you problem.

My guess is that addRow1 is not adding the TR in quite the
right spot, though IE is normally very tollerant of stuff
like that.

Careful of wrapping...

<html>
<head>
<title>Insert Row</title>

<script type="text/javascript">
function addRow1(stbl) {
alert(stbl.rows.length + " : " + stbl.firstChild.nodeName);
var newr = document.createElement('tr');
var newc = document.createElement('td');
var newT1 = document.createElement('p')
var newT2 = document.createTextNode("A new para.");
var newT3 = document.createElement('hr')

newc.appendChild(newT1);
newc.appendChild(newT2);
newc.appendChild(newT3);
newr.appendChild(newc);
stbl.appendChild(newr);

// Test that DOM stuff works without the table
var bodyRef = document.getElementsByTagName("body").item(0);
var newT4 = document.createElement('p')
var newT5 = document.createTextNode("A new para.");
bodyRef.appendChild(newT4);
bodyRef.appendChild(newT5);

}

function addRow2(r) {
var newr = document.createElement('tr');
var newc = document.createElement('td');
newc.innerHTML = "blah blah blah <br><hr>";

newr.appendChild(newc);
var rParent = r.parentNode;
rParent.insertBefore(newr,r.nextSibling);
}

function showDOM() {
var msg = "";
function listNodes(n) {
msg += n.nodeName + "\n";
for (var i=0; i<n.childNodes.length; i++) {
listNodes(n.childNodes);
}
}

listNodes(document.getElementById("aTable"));
alert(msg);
}
</script>

</head>
<body>
<table id="aTable" border="1">
<tr id="aRow"><td>Here is aRow</td></tr>
</table>
<br>
<form action="" name="aForm">
<input type="button" value="add row 1" onclick="
addRow1(document.getElementById('aTable'));
">
<input type="button" value="add row 2" onclick="
addRow2(document.getElementById('aRow'));
">
<input type="button" value="Show DOM tree"
onclick="showDOM();">
</form>

</body>
</html>
 
R

Richard Cornford

necromonger said:
I've got this code that creates a new new row and cell. I
then put some text into the cell with innerHTML - works
beautifully with Firefox but fails with IE. I guess IE
doesn't support this way of doing it, but is there
another way of doing it with DOM?

newr = document.createElement('tr');

stbl.appendChild(newr);
newc = document.createElement('td');

newr.appendChild(newc);
newr.cells[0].innerHTML = (nr+1)+". "+sa[ti][nr + 1]+"<br><hr>";

Using the identifier name - stbl - implies that it is a TABLE element to
which you are appending the row. In DOM (and HTML) terms that is
structurally incorrect as TR elements may only be children of TBODY,
THEAD and TFOOT elements. This often causes novices problems when
building tables dynamically as in HTML TBODY elements may be implied. In
the HTML DTDs the opening and closing TBODY tags are optional. They do
not need to be explicitly included in HTML source code, but TBODY
elements exist in corresponding DOMs as a result of the HTML parser
encountering a TR outside of any of the elements that are allowed to
contain it.

Richard.
 
R

RobG

necromonger said:
Thanks ROb. You've mentioned I should "insert" the row into the table,
how do I do that? isnt appendChild doing it already (internally?)
[snip]

Read Richard's post below. I'd figured the bit about the TBODY from
the tree display, but only on the bus home from work. So Richard gave
me the heart to try again. So the add row function now has a findTbody
function too - it gets the first TBODY after the TABLE reference that
you pass. The reason you need this is because you can't guarantee that
the first child of a table will be a tbody - in Safari and Firefox it's
a text node.

If you have a row ref, it's simpler to use the insertBefore/nextSibling
method.

Here's some code anyway, and have fun. I've added comments as
appropriate, you may wish to trim them out.

Oh, I added an index to the showDOM function to make it easier to tell
children and siblings.

<html>
<head>
<title>Insert Row</title>

<script type="text/javascript">

// Add a row to a table
function addRow1(stbl) {

// find the first tbody tag
var tB = findTbody(stbl);

// create the elements
var newr = document.createElement('tr');
var newc = document.createElement('td');

// append the HTML to the td
newc.innerHTML = "blah blah blah <br><hr>";

// append the td to the tr
newr.appendChild(newc);

// append the tr to the tbody
tB.appendChild(newr);
}

// Pass a tableRef and returns the first tBody
function findTbody(t) {
function readTree(u) {
for (var j=0; j<u.childNodes.length; j++) {
if (u.childNodes[j].nodeName == 'TBODY') {

// break out if we found a tbody
return u.childNodes[j];
}
// otherwise keep looking
readTree(u.childNodes[j]);
}
}
var x = readTree(t);
return x;
}

// shows the DOM with index
// only good for IE as other DOM
// viewers are better
function showDOM() {
var msg = "";
function listNodes(n,x) {
msg += x + ' ' + n.nodeName + "\n";
for (var i=0; i<n.childNodes.length; i++) {
listNodes(n.childNodes,x + '.' + i);
}
}
listNodes(document.getElementById("aTable"),'0');
alert(msg);
}

// demonstrates adding a row after a row
// using insertBefore/nextSibling method
function addRow2(r) {
var newr = document.createElement('tr');
var newc = document.createElement('td');
newc.innerHTML = "blah blah blah <br><hr>";

newr.appendChild(newc);
var rParent = r.parentNode;
rParent.insertBefore(newr,r.nextSibling);
}

</script>

</head>
<body>
<table id="aTable" border="1">
<tr id="aRow"><td>Here is aRow</td></tr>
</table>
<br>
<form action="" name="aForm">
<input type="button" value="add row 1" onclick="
addRow1(document.getElementById('aTable'));
">
<input type="button" value="add row 2" onclick="
addRow2(document.getElementById('aRow'));
">
<input type="button" value="Show DOM tree"
onclick="showDOM();">
</form>

</body>
</html>
 
V

VK

The Table Object Model cannot be manipulated in such way.

var myTable = getElementById('myTable');
var myRow = myTable.insertRow();
if (myRow != null) {
var myCell = myRow.insertCell();
myCell.innerHTML = '<b>It works !!!!!!!!</b>';
}
else {
window.alert('You can not change a data-bound table. You have to change the
data source itself');
}


More of useful reading:
http://msdn.microsoft.com/workshop/author/tables/buildtables.asp
 
F

Fred Oz

VK said:
The Table Object Model cannot be manipulated in such way.
[snip]

Yes it can. The post you refer to tried to modify a TR using innerHTML.
You can modify the contents of a cell (td) with innerHTML, which is
what the OP was trying to do after creating the row and cell with DOM
methods.

Cheers, Fred.
 
N

necromonger

Thanks RIchard, Rob,

Rob - nice of you to put in some code. Let me play around with that and
see if I get it working the way I want and I'll post an update.
Hmm...dint think a simple one would turn out this complicated! thanks to
IE >:/ :(

necromonger said:
Thanks ROb. You've mentioned I should "insert" the row into the table,
how do I do that? isnt appendChild doing it already (internally?)

[snip]

Read Richard's post below. I'd figured the bit about the TBODY from
the tree display, but only on the bus home from work. So Richard gave
me the heart to try again. So the add row function now has a findTbody
function too - it gets the first TBODY after the TABLE reference that
you pass. The reason you need this is because you can't guarantee that
the first child of a table will be a tbody - in Safari and Firefox it's
a text node.

If you have a row ref, it's simpler to use the insertBefore/nextSibling
method.

Here's some code anyway, and have fun. I've added comments as
appropriate, you may wish to trim them out.

Oh, I added an index to the showDOM function to make it easier to tell
children and siblings.

<html>
<head>
<title>Insert Row</title>

<script type="text/javascript">

// Add a row to a table
function addRow1(stbl) {

// find the first tbody tag
var tB = findTbody(stbl);

// create the elements
var newr = document.createElement('tr');
var newc = document.createElement('td');

// append the HTML to the td
newc.innerHTML = "blah blah blah <br><hr>";

// append the td to the tr
newr.appendChild(newc);

// append the tr to the tbody
tB.appendChild(newr);
}

// Pass a tableRef and returns the first tBody
function findTbody(t) {
function readTree(u) {
for (var j=0; j<u.childNodes.length; j++) {
if (u.childNodes[j].nodeName == 'TBODY') {

// break out if we found a tbody
return u.childNodes[j];
}
// otherwise keep looking
readTree(u.childNodes[j]);
}
}
var x = readTree(t);
return x;
}

// shows the DOM with index
// only good for IE as other DOM
// viewers are better
function showDOM() {
var msg = "";
function listNodes(n,x) {
msg += x + ' ' + n.nodeName + "\n";
for (var i=0; i<n.childNodes.length; i++) {
listNodes(n.childNodes,x + '.' + i);
}
}
listNodes(document.getElementById("aTable"),'0');
alert(msg);
}

// demonstrates adding a row after a row
// using insertBefore/nextSibling method
function addRow2(r) {
var newr = document.createElement('tr');
var newc = document.createElement('td');
newc.innerHTML = "blah blah blah <br><hr>";

newr.appendChild(newc);
var rParent = r.parentNode;
rParent.insertBefore(newr,r.nextSibling);
}

</script>

</head>
<body>
<table id="aTable" border="1">
<tr id="aRow"><td>Here is aRow</td></tr>
</table>
<br>
<form action="" name="aForm">
<input type="button" value="add row 1" onclick="
addRow1(document.getElementById('aTable'));
">
<input type="button" value="add row 2" onclick="
addRow2(document.getElementById('aRow'));
">
<input type="button" value="Show DOM tree"
onclick="showDOM();">
</form>

</body>
</html>
 
N

necromonger

But richard, this thing works fine in Firefox.(of course, I'll correct
it structurally later on). What I see doesnt work in IE is that it
throws an error for

tbl.rows[0].cells[0].innerHTML (not supported error)

and if i do newc.innerHTML = "blah blah" and then do appendchild - it
throws no error but shows no table either :( firefox works in both
cases. I'm at my wits end to make it work for IE but retaining my DOm
code as much as possible.

Richard said:
necromonger said:
I've got this code that creates a new new row and cell. I
then put some text into the cell with innerHTML - works
beautifully with Firefox but fails with IE. I guess IE
doesn't support this way of doing it, but is there
another way of doing it with DOM?

newr = document.createElement('tr');

stbl.appendChild(newr);
newc = document.createElement('td');

newr.appendChild(newc);
newr.cells[0].innerHTML = (nr+1)+". "+sa[ti][nr + 1]+"<br><hr>";


Using the identifier name - stbl - implies that it is a TABLE element to
which you are appending the row. In DOM (and HTML) terms that is
structurally incorrect as TR elements may only be children of TBODY,
THEAD and TFOOT elements. This often causes novices problems when
building tables dynamically as in HTML TBODY elements may be implied. In
the HTML DTDs the opening and closing TBODY tags are optional. They do
not need to be explicitly included in HTML source code, but TBODY
elements exist in corresponding DOMs as a result of the HTML parser
encountering a TR outside of any of the elements that are allowed to
contain it.

Richard.
 
R

Richard Cornford

RobG wrote:
.... So the add row function now has a findTbody function
too - it gets the first TBODY after the TABLE reference
that you pass. ...
<snip>

You may be interested to here that the W3C HTML DOM specification
defines a - tbodies - property of TABLE elements that is a collection
containing all of the TBODYs in a table. It isn't quite universally
supported even on otherwise quite complete W3C DOM browsers but it would
always be my first port of call, possibly with -
table.getElementsByTagName('TBODY') - my second.

Richard.
 
R

Richard Cornford

necromonger said:
But richard, this thing works fine in Firefox.(of course,
I'll correct it structurally later on). ...

I will bet that if you examine the constructed DOM you will find that
Firefox has added the intervening TBODY element for you, if not then you
got lucky (it happens), but there is still not reason to expect it to
work in other browsers (indeed the W3C Core DOM spec says an exception
should be thrown when an attempt is made to construct an invalid tree,
though I can see why people are reluctant to implement that in HTML web
browsers).

Oh, and please don't top post to comp.lang.javascript.

Richard.
 
R

RobG

necromonger said:
Thanks RIchard, Rob,

Rob - nice of you to put in some code. Let me play around with that and
see if I get it working the way I want and I'll post an update.
Hmm...dint think a simple one would turn out this complicated! thanks to
IE >:/ :(
[snip]

So I guess you have a couple of options here:

You can use Richard's table.getElementsByTagName, it
returns a collection so you likely need to pick where you
want to insert your row (after the last one?). It will
probably do the job just fine 999 out of 1,000 and you are
in control of whether it works or not (i.e. it breaks
depending on the HTML you compose, not how the browser
reads it).

One caveat: if you intend to put in an empty
table (e.g. <table></table>) then add rows, some browsers
do not put in a tbody (e.g. Safari) even though they do put
in a tbody if there are rows there in the HTML. So you
can't add rows using JD. If this is your intent, make sure
you put a tbody in the HTML.

You can use the tree climbing method to find the first
tbody, but it's got pretty much the same issues as the
getElements... method and is likely overly complex - it
worked but I like getElements... better - it's simple.

Another method is to put in a row, then use style to hide
it, like:

<tr style="display: none;">...td's as required...</tr>

Now you have an apparently empty table and an
explicit place to add rows and can use the
insertBefore/nextSibling method. No more tbody issues.

It can even save you a lot of work if you have lots of
cells, so you can use cloneNode to clone an entire row,
then insert your HTML into cells as required rather than
using DOM methods to create all the elements - remember to
change the display property of your clone to '' or it'll
inherit the originals 'none'.

Gosh, spoilt for choice - Rob.


PS I keep forgetting that you can use things like:

var theTDs = tableRef.getElementsByTagName('td');

It even works getting the LIs in an OL or UL.
 
V

VK

The Table Object Model cannot be manipulated in such way.
Yes it can.

No, it can not :)

I mean it is sometimes possible on some browsers, but it should not be used.
It's like use an assembler for direct memory patch instead of using proper
object's methods. May work, may not, may blow up in your face.

Using TOD as I suggested gives you the proper references to the rows and
cells, so you can apply innerHTML method to the proper object in the proper
way:
....
var myCell = myRow.insertCell();
myCell.innerHTML = '<b>It works !!!!!!!!</b>';
....
 
F

Fred Oz

VK wrote:
[snip]
var myCell = myRow.insertCell();
myCell.innerHTML = '<b>It works !!!!!!!!</b>';
...

The OP had:

newr = document.createElement('tr');
stbl.appendChild(newr); // here's the error
newc = document.createElement('td');
newr.appendChild(newc);
newr.cells[0].innerHTML = (nr+1)+". "+sa[ti][nr + 1]+"<br><hr>";

I fail to see the difference - but I've been wrong before... You both
used DOM methods to create a row and a cell, then append the cell to the
row. You both then use innnerHTML to write the content of the cell.

The order in which the OP did things was a bit strange though...

The OP's problem was appending the row to the table node, not the
tablebody. Firefox shrugged and just put the row in the right place, IE
barfed 'cos it wanted a tbody - I would have bet money on the exact
opposite happening, but wonders never cease.

Cheers, Fred.
 
V

VK

newr = document.createElement('tr');
stbl.appendChild(newr); // here's the error

Sorry, but the error was starting the first string. It mutually agreed that
the table structure would not be operated this way (through the
createElement/appendChild methods).
These methods are mostly for inline text-containing blocks like <p>, <ol>
and so on.

http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/DOM.txt


Most of the postings has made it sound like Firefox behaves according to
DOM, and IE (as usual, what else new, blah-blah :) goes by its proprietary
way.

This is why I raised my weak voice to say that the truth is just the
opposite: IE does what prescribed, and Firefox is cheating on DOM.
 
V

VK

... Firefox is cheating on DOM.

I would add: dangerously cheating. TOM has been created not to complicate
developers' life.
First of all, up till now tables are still the main holding construction of
any page.
Secondly, any table be a data bound / data island. I saw some tables you
need a good coffee or whisky just to get where the data coming from, and
where the text is getting its formatting from.

createElement goes by Java's way: first you are creating an object "out of
space and time". Naturally you can create ANY object and use ANY of its
methods as long as it stays in that abstraction purgatory. The hell may rise
when it's time to add it to the graphics context (gc).

TOM was intended to force you either to create a table from the scratch, or
to get an actual object first from the gc and then try to do some stuff with
it. This is the only way for the system to check for a potential gc havoc.

P.S. I don't have Firefox handy right now. Any volunteers for an afternoon
fun? Did you try to createElement(row) and place it right into the document?
(and screw the "unnecessary" <table></table> ). I don't say it will work for
sure, but a bit curious...
 
L

Lasse Reichstein Nielsen

VK said:
Sorry, but the error was starting the first string. It mutually agreed that
the table structure would not be operated this way (through the
createElement/appendChild methods).

The W3C DOM 2 HTML makes no statement that createElement and appendChild
cannot be used to add a new table row to a table.

The text "The create* and delete* methods on the table allow authors
to construct and modify tables." is not excluding other ways to create
and add rowgroups, rows or cells.

Also, all DOM-supporting browsers will allow adding rows created with
createElement - you just have to add the row to the tbody element
instead of the table element in order to add the row to the table.
These methods are mostly for inline text-containing blocks like <p>, <ol>
and so on.

No, the methods "createElement" and "appendChild" are Core DOM
functionality, belonging to Document and Node respectively.

Reading the HTML DOM specification, HTMLDocument inherits from
Document and HTMLElement inherits from Node (through Element). It
should work.

Also, from <URL:http://www.w3.org/TR/DOM-Level-1/introduction.html>
they are using, of all things, a table element as demonstration
of the DOM (the image is missing from the text version).
This is why I raised my weak voice to say that the truth is just the
opposite: IE does what prescribed, and Firefox is cheating on DOM.

Agreed on that, because it adds the row to the tbody, and not to the
element that had its appendChild called.

/L
 
N

necromonger

I finally got it working by creating a table dynamically, attaching tr
and td to it and then doing a nc.innerHTML. Worked for both IE and
Firefox (I attached the table to a div)

Sorry richard -- dint get the 'top post' thing...do you mean dont keep
all the past conversation? or is it something else? tell me and I wont
do it again :)
 
R

Randy Webb

necromonger said:
Sorry richard -- dint get the 'top post' thing...do you mean dont keep
all the past conversation? or is it something else? tell me and I wont
do it again :)

It is the posting style of putting your answer above what you are
replying to. Read the signature :)



--
Randy
comp.lang.javascript FAQ - http://jibbering.com/faq
Answer:It destroys the order of the conversation
Question: Why?
Answer: Top-Posting.
Question: Whats the most annoying thing on Usenet?
 

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,768
Messages
2,569,574
Members
45,048
Latest member
verona

Latest Threads

Top