By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
443,750 Members | 1,471 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 443,750 IT Pros & Developers. It's quick & easy.

adding/deleting dynamic table row, rowIndex

P: n/a
I am trying hard for days now to add and delete rows to a table. I
could really use some help...

Each row contains two buttons (images) - 'add row' and 'delete row'.
When the user clicks add row within a specific cell/row, the index of
that row should be passed to a function that creates a new row using
that index (the new row should be added directly below the row where
the user clicked. The new row should contain all of the cells and html
in the cells from the row above, including the buttons/images. If a
user clicks delete row, the index of the row with the delete button
should pass to the function that deletes the row.

I would greatly appreciate any help - I'm new to this. The more
thorough the explanation, the better. I've seen the other postings in
this group and I can't seem to apply the logic to my situation.

THANKS

Jul 23 '05 #1
Share this Question
Share on Google+
10 Replies


P: n/a
AdamG wrote:
I am trying hard for days now to add and delete rows to a table. I
could really use some help...


You probably want to use cloneNode, some code follows. Be aware that
you will also clone any element ids or names too. Post again if you
need further help.
<html><head><title>Add & Delete Table Rows...</title>

<script type="text/javascript">

/* cloneRow
* Clones a row when a cell has been clicked on
* Given a reference to the cell, clones the row and inserts it
* before nextSibling.
* If the nextSibling doesn't exist, it doesn't matter, the
* newElement is put immediately after the the row theThing is
* in anyway.
*/
function cloneRow(theCell) {
if( document.createElement && document.childNodes ) {
var thisRow = theCell.parentNode;
var newElement = thisRow.cloneNode(true);
thisRow.parentNode.insertBefore(newElement,thisRow .nextSibling);
}}

/* deleteRow
* Deletes a row when a cell is clicked on.
* Gets a reference to the row that the cell is in, then deltes the
* entire row from the table.
*/
function deleteRow(theCell) {
if( document.createElement && document.childNodes ) {
var thisRow = theCell.parentNode;
thisRow.parentNode.removeChild(thisRow);
}}

</script>
</head>
<body>

<table border="1">
<tr>
<td onclick="cloneRow(this);">Click here to clone the row</td>
<td>here is another cell</td>
<td onclick="deleteRow(this);">Click here to delete the row</td>
</tr>
</table>

</body></html>

--
Rob
Jul 23 '05 #2

P: n/a
On 8 Dec 2004 12:17:09 -0800, AdamG <ag*******@yahoo.com> wrote:

[snip]
When the user clicks add row within a specific cell/row, the index of
that row should be passed to a function that creates a new row using
that index (the new row should be added directly below the row where the
user clicked.
Table rows contain, amongst other properties, two named rowIndex and
sectionRowIndex. The former specifies the position within the table as a
whole. The latter specifies the position within the containing table
section: an implicit or explicit TBODY, THEAD or TFOOT element.

To get those values when a button within the row in question is activated,
use:

var button, cell, row;
if((cell = button.parentNode) && (row = cell.parentNode)) {
return row.rowIndex; // or row.sectionRowIndex
}

The easiest way to obtain a reference to the button is to use the this
operator inside the click event. I'll show that later.

It's probably obvious, but the number obtained from the rowIndex property
should be used with the table's insertRow and deleteRow methods, whilst
rowSectionIndex should be used with a table section's insertRow and
deleteRow methods.
The new row should contain all of the cells and html in the cells from
the row above, including the buttons/images.
That's simple enough. Calling

row.cloneNode(true)

will return a new row which contains everything the original did. However,
you'll have to add event listeners again as they're not copied.
If a user clicks delete row, the index of the row with the delete button
should pass to the function that deletes the row.


This will follow on from the insertion code.

[snip]

In all, you're probably looking at:

function remove(btn) {var cell, row, sect;
if((cell = button.parentNode) && (row = cell.parentNode)
&& (sect = row.parentNode) && sect.deleteRow)
{
sect.deleteRow(row.sectionRowIndex);
}
}

function insert(btn) {var cell, newRow, row, sect;
if((cell = button.parentNode) && (row = cell.parentNode)
&& row.cloneNode && (sect = row.parentNode)
&& sect.insertBefore)
{
newRow = row.cloneNode(true);
/* If you need to alter the new row
* or its contents, do it here.
*/
sect.insertBefore(newRow, row.nextSibling);
}
}

You'd call these with:

<input type="button" ... onclick="insert(this);">

and

<input type="button" ... onclick="remove(this);">

If you need more help, you'll have to show the relevant HTML you're using.

Good luck,
Mike

--
Michael Winter
Replace ".invalid" with ".uk" to reply by e-mail.
Jul 23 '05 #3

P: n/a
On Thu, 09 Dec 2004 07:56:24 +1000, RobG <rg***@iinet.net.auau> wrote:

[snip]
if( document.createElement && document.childNodes ) {
Umm, what relevance does document.createElement and document.childNodes
have to the methods and properties you're using?
var thisRow = theCell.parentNode;
var newElement = thisRow.cloneNode(true);
thisRow.parentNode.insertBefore(newElement,thisRow .nextSibling);


Test what you're actually using: don't infer. Even complete feature testing

function cloneRow(cell) {var row, section;
if((row = cell.parentNode) && row.cloneNode
&& (section = row.parentNode) && section.insertBefore)
{
section.insertBefore(row.cloneNode(true), row.nextSibling);
}
}

won't adversely affect the speed of execution to any noticable level.
However, it is probably (fairly) safe to assume that is a property that
exists on one node will exist on another.

[snip]

Mike

--
Michael Winter
Replace ".invalid" with ".uk" to reply by e-mail.
Jul 23 '05 #4

P: n/a
A few more hints, I have a tad more time at the moment.

A useful enhancement is to prevent the last row of the table from being
deleted. Get the parent of the row (which should be a tbody) and count
the rows:

var numRows = theRow.parentNode.rows.length;

if numRows <= 1, don't allow the user to delete the row. To make
sure it all works, it is probably best to put tbody elements in your
HTML. That's a belt and braces approach I guess, but removes any doubt
as to what the row parent is (read: simpler maintenance).

And a few thoughts on cloneNode:

A common use for cloneNode is when you have a form set out in a
table, like a purchase order with many inputs in each row. cloneNode
allows you to simply create another line in the form and includes any
user input too, potentially saving user input keystrokes.

It may be useful to create a function that goes through the cloned node
and selectively removes some (or all) user input that has been cloned.

A downside of using cloneNode is that you now have identical element
ids/names. If you are allowing users to add and delete new elements
in no particular order this can be a real issue.

When submitting the form, you will get multiple name/value pairs with
the same name - which can be handled OK at the server as all the
parameters are passed in sequence (though I'm not sure you can
guarantee the sequence, so don't depend on it). The real grief is when
you try to validate the form, as you can't uniquely identify elements
with identical names other than by their order in the form.

And if you clone an entire form, how do you identify one from another?

And of course there is the syntactical correctness issue of creating
invalid markup by having identical ids.

So you need to develop a scheme for creating unique ids and names and
attaching them to the elements - it can be labourious and kinda defeats
the beautiful simplicity of cloneNode, but may still be better than
creating it all from scratch.

Mike Winter shows where to do it in his post.

Provided you can overcome these issues, cloneNode is a great invention.

--
Rob
Jul 23 '05 #5

P: n/a
Michael Winter wrote:
[...]
Umm, what relevance does document.createElement and document.childNodes
have to the methods and properties you're using?

[...]

Err, excellent point. This was from some old code that I didn't clean
up properly - rushing between assignments at the moment.

My apologies to the OP and thanks to Mike. :-p

--
Rob
Jul 23 '05 #6

P: n/a
You guys have given me some fantastic advice. Thanks! I'm trying it
all right now.

I am concerned about not having unique element IDs when I use
cloneNode.

Thanks!!

Jul 23 '05 #7

P: n/a
What about using insertRow and innerHTML for each cell, instead of
using cloneNode? Would this create unique IDs for the elements?

Jul 23 '05 #8

P: n/a
On 9 Dec 2004 07:37:04 -0800, AdamG <ag*******@yahoo.com> wrote:
What about using insertRow and innerHTML for each cell, instead of using
cloneNode? Would this create unique IDs for the elements?


No. If you can show *exactly* what a row will contain and how you'd like
to change its contents, we can give you an answer.

Mike

--
Michael Winter
Replace ".invalid" with ".uk" to reply by e-mail.
Jul 23 '05 #9

P: n/a
Hi - I tried you code above. I was able to get it working - I had to
change one thing :

if((cell=btn.parentNode)..... I changed "button" to "btn", to
correspond to the parameter passed to the function (btn).

I'm now thinking about ways to make each row element unique for the
purposes of submitting the form. Any ideas on how I could submit the
results (I'm sure you have ideas). Again THANK YOU !!!!!!!!!!!!!!!!!!!

Jul 23 '05 #10

P: n/a
Hi Mike - I'll try to give you some more info, because it sounds like
you can actually help me.

Here's the code for my table:
<form name="form2" method="post" action="">
<table border="1" align="left" cellpadding="1" id="Table">
<tr>
<td height="74" colspan="4" bgcolor="#F4F4F4"><strong><font
color="#000000" size="4">Please
enter a name for the ROI Survey:</font>
<input name="Survey Name" type="text" id="Survey Name5"
value="Fiorano ESB" size="30">
</strong></td>
<td height="74"><div align="center"><a href="#"
onMouseOut="MM_swapImgRestore()"
onMouseOver="MM_swapImage('Image5','','click%20to% 20save2.gif',1)"><img
src="click%20to%20save.gif" alt="click to save" name="Image5"
width="120" height="75" border="0"></a></div></td>
</tr>
<tr valign="bottom" bgcolor="#F5F5F5">
<td width="34">&nbsp;</td>
<td width="156" height="26"><div align="left">
<p align="center"><font size="3"><strong>Enter Touch
Points</strong></font></p>
</div></td>
<td width="185"><div align="center"><font
size="3"><strong>Enter Survey
Questions</strong></font></div></td>
<td width="91"><div align="center"><font
size="3"><strong>Answer Type</strong></font></div></td>
<td width="260"><p align="center"><font
size="3"><strong><strong>Contact
Info </strong></strong></font></p></td>
</tr>
<tr valign="top">
<td valign="top"><ol>
<li></li>
</ol></td>

/*The following is the row I'd like to copy when I hit add new row -
the new row should contain a number identifier (a unique identifier) in
cell 1, blank text in cell 2, a text box and two buttons (add and
delete) in cell 3, and 4 text boxes in cell 4.

<td height="98" valign="top"> <div align="left">
<textarea name="TouchPoint_txt" cols="20" rows="3"
id="TouchPoint_txt"></textarea>
<br>
</div></td>
<td><textarea name="question_txt" cols="25" rows="4"
id="question_txt"></textarea><br>
<input name="add" type="button" onclick="insert(this);"
id="button" value="+"> <font size="1">-
add new Touch Point<br>
<input name="delete" type="button" onclick="remove(this);"
id="button" value="-"><font size="1">-
delete this Touch Point</font></font></td>
<td><select name="answer type" id="answer type">
<option selected>Number</option>
<option>List</option>
<option>Percentage</option>
<option>Text</option>
<option>Yes/No</option>
</select></td>
<td align="left" valign="top"><p> <font
size="2"><strong>Name</strong></font>
<input type="text" name="textfield5">
<font color="#000000"
size="2"><strong>Email</strong></font><strong><font color="#0000FF">
</font></strong><font color="#0000FF">
<input type="text" name="textfield6">
<br>
<font color="#000000" size="2"><strong>Name
2</strong></font>
<input name="textfield8" type="text" size="18">
<br>
<font color="#000000" size="2"><strong>Email
2</strong></font>
<input name="textfield7" type="text" size="18">
</font> </p>
</td>
</tr>
</table>
</form>

I have not had success using your code to delete a row - I am getting
no error message or action when I click it (the delete button does call
the remove(btn) function, but it's not working).

My goal is to allow the user to add rows as he/she pleases. Then they
should be able to click a button to submit the entire form - ideally
the contents of the form could be output to a server to text file, with
unique identifiers on each row.

I know this may be a poorly constructed question - sorry I'm totally
new to javascript and relatively inexperienced in programming. Your
suggestions have been great!

Jul 23 '05 #11

This discussion thread is closed

Replies have been disabled for this discussion.