Results 1 to 10 of 10

Thread: dynamic cloning/inserting a node

  1. #1
    Join Date
    Jul 2006
    Location
    just north of Boston, MA
    Posts
    1,806
    Thanks
    13
    Thanked 72 Times in 72 Posts

    Default dynamic cloning/inserting a node

    I am trying to dynamically insert a cloned node, changing the the value of some of the attributes of a "second level" clone at the same time.

    Code:
    <script type="text/javascript">
    function addOrderFormFields(dynamicFormReadId, dynamicFormWriteId, counter, counterStart)
    {
    	if(!counters[counter])
    		counters[counter] = counterStart;
    		
    	counters[counter]++;
    
    	var newFields = document.getElementById(dynamicFormReadId).cloneNode(true);
    	newFields.id = '';
    	var newField = newFields.childNodes;
    	
            /* initiate the first level (td) loop */
    	for (var i=0;i<newField.length;i++)
    	{
    		var iFields = newField[i].cloneNode(true);
    		var iField = iFields.childNodes;
    		
                    /* initiate the second level (input) loop */
    		for(var j=0; j<iField.length; j++)
    		{
    			var theName  = iField[j].name;
    			if (theName)
    			{
    				iField[j].name = theName.substr(0, theName.length - 1) + counters[counter];				
    				iField[j].value = ''; /* clear any default value that may be present */
    			}
    		}
    	}
    
    	var insertHere = document.getElementById(dynamicFormWriteId);
    	insertHere.parentNode.insertBefore(newFields,insertHere);
    }
    </script>
    <table>
    	<tr id="dynamicFormReadPart">
    		<td><input type="text" name="partQuantity0" value="{top.QUANTITY}" size="5"></td>
    		<td><input type="text" name="partNumber0" value="{top.NUMBER}"></td>
    		<td><input type="text" name="partDescription0" value="{top.DESCRIPTION}" size="50"></td>
    		<td><input type="text" name="partSerial0" value="{top.SERIAL}"></td>
    	</tr>
          	<tr id="dynamicFormWritePart"><!-- USED AS PLACEHOLDER TO INSERT DYNAMIC FIELDS -->&nbsp;</tr>
    	<tr>
    		<td colspan="4" align="left"><input type="button" value="Add More Parts to Order" onclick="javascript:addOrderFormFields('dynamicFormReadPart', 'dynamicFormWritePart', 'c0', 0)"></td>
    	</tr>
    </table>
    This script will insert the new table row correctly, however it is not incrementing the name attribute of the input fields.

    any help would be appreciated.
    Last edited by boogyman; 11-11-2008 at 08:22 PM. Reason: resolved

  2. #2
    Join Date
    Jul 2008
    Posts
    128
    Thanks
    0
    Thanked 17 Times in 16 Posts

    Default

    Quote Originally Posted by boogyman View Post
    I am trying to dynamically insert a cloned node, changing the the value of some of the attributes of a "second level" clone at the same time.

    Code:
    <script type="text/javascript">
    function addOrderFormFields(dynamicFormReadId, dynamicFormWriteId, counter, counterStart)
    {
    	if(!counters[counter])
    		counters[counter] = counterStart;
    		
    	counters[counter]++;
    
    	var newFields = document.getElementById(dynamicFormReadId).cloneNode(true);
    	newFields.id = '';
    	var newField = newFields.childNodes;
    	
            /* initiate the first level (td) loop */
    	for (var i=0;i<newField.length;i++)
    	{
    		var iFields = newField[i].cloneNode(true);
    There is no need to clone the children of a cloned parent. This causes the name to be applied to the wrong node
    Code:
    		iField[j].name = theName.substr(0, theName.length - 1) + counters[counter];
    This will only work properly up to 9. I would use:
    Code:
    iField[j].name = theName.replace(/(.*?)(\d*)$/, "$1"+counters[counter]);

  3. #3
    Join Date
    Jul 2006
    Location
    just north of Boston, MA
    Posts
    1,806
    Thanks
    13
    Thanked 72 Times in 72 Posts

    Default

    Quote Originally Posted by clueful View Post
    There is no need to clone the children of a cloned parent. This causes the name to be applied to the wrong node
    Yeah I thought that would be the case, however using just one loop wouldn't even obtain the attributes of the <input> tags. Once I created that second loop, I was able to accurately "grab" and update the tags, however the calculation still wouldn't properly update, hense why I posted here

    This will only work properly up to 9. I would use:
    Code:
    iField[j].name = theName.replace(/(.*?)(\d*)$/, "$1"+counters[counter]);
    Regular expressions are generally slower, so I wanted to avoid them as much as possible.
    I will assume you mean IE 9? above, and what exactly are you referring to by

    "$1"

    Thanks for the help.

  4. #4
    Join Date
    Mar 2005
    Location
    SE PA USA
    Posts
    30,495
    Thanks
    82
    Thanked 3,449 Times in 3,410 Posts
    Blog Entries
    12

    Default

    I would use a different approach. Once I cloned the node as many times as I wanted to and inserted them into the markup, I would use the cloned nodes' new parent node (the table if I am following this correctly - actually the tbody, but the table will do) to cycle through its tagName node list, something like:

    Code:
    var t = reference to the table;
    for(var c = 0, els = t.getElementsByTagName('*'), i = 0; i < els.length; ++i)
     if(els[i] == t.rows[c + 1]){
      ++c;
      if (c > 0) //not positive if this is right for your markup, but should work if the markup were simplified
       els[i].id = '';
     } else if(/^part/.test(els[i].name)){
      els[i].name = els[i].name.replace(/\d+/, '') + c;
     }
    Last edited by jscheuer1; 11-11-2008 at 05:00 PM.
    - John
    ________________________

    Show Additional Thanks: International Rescue Committee - Donate or: The Ocean Conservancy - Donate or: PayPal - Donate

  5. #5
    Join Date
    Mar 2005
    Location
    SE PA USA
    Posts
    30,495
    Thanks
    82
    Thanked 3,449 Times in 3,410 Posts
    Blog Entries
    12

    Default

    Maybe even:

    Code:
    var t = reference to the table;
    for(var c = 0, els = t.getElementsByTagName('*'), i = 0; i < els.length; ++i)
     if(els[i] == t.rows[c + 1]){
      ++c;
      if (els[i].id != 'dynamicFormWritePart')
       els[i].id = '';
      else break;
     } else if(/^part/.test(els[i].name)){
      els[i].name = els[i].name.replace(/\d+/, '') + c;
     }
    - John
    ________________________

    Show Additional Thanks: International Rescue Committee - Donate or: The Ocean Conservancy - Donate or: PayPal - Donate

  6. The Following User Says Thank You to jscheuer1 For This Useful Post:

    boogyman (11-11-2008)

  7. #6
    Join Date
    Jul 2006
    Location
    just north of Boston, MA
    Posts
    1,806
    Thanks
    13
    Thanked 72 Times in 72 Posts

    Default

    Quote Originally Posted by jscheuer1 View Post
    Maybe even:

    Code:
    var t = reference to the table;
    for(var c = 0, els = t.getElementsByTagName('*'), i = 0; i < els.length; ++i)
     if(els[i] == t.rows[c + 1]){
      ++c;
      if (els[i].id != 'dynamicFormWritePart')
       els[i].id = '';
      else break;
     } else if(/^part/.test(els[i].name)){
      els[i].name = els[i].name.replace(/\d+/, '') + c;
     }
    This is getting closer, however the term "take two backwards to take one forwards" applies.

    This will in fact increment the elements as I would like, however
    Code:
    if (els[i].id != 'dynamicFormWritePart')
       els[i].id = '';
    is now deleting the "read" id from the form, so I am unable to clone it again. I will work on bypassing the initial element that gets cloned, and update the script here.

  8. #7
    Join Date
    Jul 2006
    Location
    just north of Boston, MA
    Posts
    1,806
    Thanks
    13
    Thanked 72 Times in 72 Posts

    Default

    I know this is an adhoc way of doing it, but after the last loop, I just reassigned the appropriate table row the correct id.

    John, or anyone else, if you can think of a better way to accomplish this within the loop please don't hesitate to share. Below is an updated script that works

    Code:
    <script type="text/javascript">
    function addOrderFormFields(dynamicFormReadId, dynamicFormWriteId)
    {
    	var newFields = document.getElementById(dynamicFormReadId).cloneNode(true);
    	var insertHere = document.getElementById(dynamicFormWriteId);
    	insertHere.parentNode.insertBefore(newFields,insertHere);
    	
    	var t = document.getElementById('partFields');
    	for(var c = 0, els = t.getElementsByTagName('*'), i = 0; i < els.length; ++i)
    	{
    		if(els[i] == t.rows[c + 1])
    		{
    			++c;
    			if(els[i].id != 'dynamicFormWritePart')
    				els[i].id = '';
    			else 
    				break;
    		} 
    		else if(/^part/.test(els[i].name))
    			els[i].name = els[i].name.replace(/\d+/, '') + c;
    	}
    	
    	els[6].id = 'dynamicFormReadPart';
    }
    </script>
    
    <table id="partFields" summary="Parts associated with this order request">
    	<tbody>
    		<tr>
    			<th>Qty</th>
    			<th>Part Number</th>
    			<th>Part Description</th>
    			<th>Serial</th>
    		</tr>
    		<tr id="dynamicFormReadPart">
    			<td><input name="partQuantity0" value="" size="5" type="text"></td>
    			<td><input name="partNumber0" value="" type="text"></td>
    			<td><input name="partDescription0" value="" size="50" type="text"></td>
    			<td><input name="partSerial0" value="" type="text"></td>
    		</tr>
    		<tr id="dynamicFormWritePart"><!-- USED AS PLACEHOLDER TO INSERT DYNAMIC FIELDS --></tr>
    	</tbody>
    </table>
    <input value="Add More Parts to Order" onclick="javascript:addOrderFormFields('dynamicFormReadPart', 'dynamicFormWritePart')" type="button">

  9. #8
    Join Date
    Mar 2005
    Location
    SE PA USA
    Posts
    30,495
    Thanks
    82
    Thanked 3,449 Times in 3,410 Posts
    Blog Entries
    12

    Default

    The code I wrote shouldn't even look at row 0 for id changing:

    Code:
    if(els[i] == t.rows[c + 1]){ // we are already at least to row 1
      ++c;
      if (els[i].id != 'dynamicFormWritePart')
       els[i].id = '';
      else break;
     }
    <tr id="dynamicFormReadPart"> is row 0. But if I've miscalculated or if you've put a header row in there later:

    Code:
    if(c > 1 && els[i].id != 'dynamicFormWritePart')
    Instead of cloning the row by its id in the first place, you may clone it as a member of the table's rows collection. The numbers may all be made to work out any way you like if you just count the rows starting with 0 for the first one and adjusting c's initial value and any tests against and uses of c accordingly.

    You could also skip having a dynamicFormWritePart id by simply (as long as their is a last row to insert before, otherwise you could simply append):

    Code:
    table.rows[table.rows.length - 1].parentNode.insertBefore(clonedRow, table.rows[table.rows.length - 1]);
    - John
    ________________________

    Show Additional Thanks: International Rescue Committee - Donate or: The Ocean Conservancy - Donate or: PayPal - Donate

  10. The Following User Says Thank You to jscheuer1 For This Useful Post:

    boogyman (11-11-2008)

  11. #9
    Join Date
    Jul 2006
    Location
    just north of Boston, MA
    Posts
    1,806
    Thanks
    13
    Thanked 72 Times in 72 Posts

    Default

    Quote Originally Posted by jscheuer1 View Post
    The code I wrote shouldn't even look at row 0 for id changing:

    Code:
    if(els[i] == t.rows[c + 1]){ // we are already at least to row 1
      ++c;
      if (els[i].id != 'dynamicFormWritePart')
       els[i].id = '';
      else break;
     }
    <tr id="dynamicFormReadPart"> is row 0. But if I've miscalculated or if you've put a header row in there later:
    There was always a header row, I probably just forgot to include it in my example.
    Code:
    <table id="partFields" summary="Parts associated with this order request">
    	<tbody>
    		<tr>
    			<th>Qty</th>
    			<th>Part Number</th>
    			<th>Part Description</th>
    			<th>Serial</th>
    		</tr>
    		<tr id="dynamicFormReadPart">
    			<td><input name="partQuantity0" value="" size="5" type="text"></td>
    			<td><input name="partNumber0" value="" type="text"></td>
    			<td><input name="partDescription0" value="" size="50" type="text"></td>
    			<td><input name="partSerial0" value="" type="text"></td>
    		</tr>
    		<tr id="dynamicFormWritePart"><!-- USED AS PLACEHOLDER TO INSERT DYNAMIC FIELDS --></tr>
    	</tbody>
    </table>
    Code:
    if(c > 1 && els[i].id != 'dynamicFormWritePart')
    I tried that, and I also substituted the c for an i neither of which worked


    You could also skip having a dynamicFormWritePart id by simply (as long as their is a last row to insert before, otherwise you could simply append):
    Well the only purpose of that last row is for the insert, however the method you suggested is still more elegant then the one I was proposing so I updated it accordingly.


    below is the JS file as it reads right now. The html table hasnt changed from my last example

    Code:
    function addOrderFormFields(dynamicFormReadId, dynamicFormWriteId)
    {
    	var newFields = document.getElementById(dynamicFormReadId).cloneNode(true);	
    	var t = document.getElementById('partFields');
    	
    	/* insert the cloned node */
    	t.rows[t.rows.length - 1].parentNode.insertBefore(newFields, t.rows[t.rows.length - 1]);
    	
    	/* re-assign the input name attributes */
    	for(var c = 0, els = t.getElementsByTagName('*'), i = 0; i < els.length; ++i)
    	{
    		if(els[i] == t.rows[c + 1])
    		{
    			++c;
    			if(c>1 && els[i].id != 'dynamicFormWritePart')
    				els[i].id = '';
    			else 
    				break;
    		} 
    		else if(/^part/.test(els[i].name))
    			els[i].name = els[i].name.replace(/\d+/, '') + c;
    	}
    }

  12. #10
    Join Date
    Jul 2006
    Location
    just north of Boston, MA
    Posts
    1,806
    Thanks
    13
    Thanked 72 Times in 72 Posts

    Default

    changed the c+1 to c+2 to bypass the header row and the row I wish to clone

    Code:
    function addOrderFormFields(dynamicFormReadId, dynamicFormWriteId, tbl)
    {
    	/* clone the appropriate node */
    	var newFields = document.getElementById(dynamicFormReadId).cloneNode(true);	
    	/* get the table being cloned */
    	var t = document.getElementById(tbl);
    	
    	/* remove any default values of the child elements */
    	var newField = newFields.childNodes;
    	for(var j=0; j<newField.length; j++)
    	{
    		newField[j].value = '';
    	}
    	
    	/* insert the cloned node */
    	t.rows[t.rows.length - 1].parentNode.insertBefore(newFields, t.rows[t.rows.length - 1]);
    
    	/* re-assign the input 'name' and 'id' attributes accordingly */
    	for(var c = 0, els = t.getElementsByTagName('*'), i = 0; i < els.length; ++i)
    	{
    		if(els[i] == t.rows[c + 2])
    		{
    			++c;
    			
    			if(els[i].id != dynamicFormWriteId)
    				els[i].id = '';
    			else 
    				break;
    		} 
    		else if(/^part/.test(els[i].name))
    		{
    			els[i].name = els[i].name.replace(/\d+/, '') + c;
    		}
    	}
    }
    Thanks John for your help

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •