Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Change name attribute of input/select field nested in a cloned table for dynamic form entry - Javascript

I'm designing a dynamic input form that essentially acts as a user GUI for creating tables in a mysql database.

The Javascript

var counter = 0;
function moreFields() {
    counter++;
    var newFields = document.getElementById('poptemplate').cloneNode(true);
    newFields.id = '';
    newFields.style.display = 'block';
    var newField = newFields.childNodes;
    for (var i=0;i<newField.length;i++) {
        var fieldname = newField[i].name;
        if (fieldname){
            newField[i].name = fieldname + counter;
            }
    }
    var insertHere = document.getElementById('catidtable');
    insertHere.parentNode.appendChild(newFields);
    }
window.onload = moreFields;

The HTML

<div id="poptemplate" style="display: none" >
<table border="3">
<tr>
    <td>Field Name:</td>
    <td><input class="renameme" form="catform" type="text" name="fieldname_input" /></td>
</tr>
<tr>
    <td>Data Type:</td>
    <td><?php $typedown->displayList(); ?></td>
</tr>
<tr>
    <td colspan='2'><input type="button" value="Remove Field" onclick="this.parentNode.parentNode.parentNode.parentNode.removeChild(this.parentNode.parentNode.parentNode);" /></td>
</tr>
</table>
</div>

The Problem

The problem is that when new fields are added to the form, they retain the same name designators from the original clone. (Clone structure is 'poptemplate' div in code above.)

Having taught myself most of my web developing skills from research, I have located this script, now modified, (original source: http://www.quirksmode.org/dom/domform.html) in order to clone the template and insert it into the page (with an unshown jquery function that merely calls the JS function when the Add Field button is clicked).

The problem is, the JS, while it clones the DIV successfully and places it, the loop involved does not delve deep enough into the node structure of my template to find the input fields and change their names.

One input field is a drop-down list that is populated through a mysql query with php, however its location in the node structure should be at the same level as the text input. (i.e. <Table><tr><td><input(or/)select>)

The Attempt At Fixing Part 1

function moreFields() {
    counter++;
    var newFields = document.getElementById('poptemplate').cloneNode(true);
    newFields.id = '';
    newFields.style.display = 'block';
    var newField = newFields.childNodes; //Table level of poptemplate
    if (newField.hasChildNodes()){//If the table has children, and it does, loop through them
     for (var i=0;i<newField.length;i++) {
        var x = newField.rows[i].cells.length; //how many cells you got in your row
            if (x>0;){ //if its more than 0, look at the cells
            for (var r = 0;r<x;r++) {
                var td = newField.rows[0].cell[r]; //td is equal to the td level time to check to see if it has input or select
                    var k = td.getElementsByTagName("select");
                    if (k.hasChildren()){
                    k.firstChild.setAttribute(name, name + counter);
                    }
                    var p = td.getElementsByTagName("input");
                    if (p.hasChildren()){
                    p.firstChild.setAttribute(name, name + counter);
                    }
                                    }
                    }
                                        }
}                                           
    var insertHere = document.getElementById('catidtable');
    insertHere.parentNode.appendChild(newFields);
}
window.onload = moreFields;

Attempt At The Fix Part 2

After following through with a suggestion from briansol, I have the following modified java script that still does not follow through with what it is supposed to do on execution. I have left the unnecessary, however useful, line of code inputs[index].value = inputs[index].name + counter; for troubleshooting purposes.

var counter = 0;
function moreFields() {
    counter++;
    var index, inputs;
    var newFields = document.getElementById('poptemplate').cloneNode(true);
    newFields.id = newFields.id+counter;
    newFields.style.display = 'block';
    var newField = newFields.childNodes;
    var insertHere = document.getElementById('catidtable');
    insertHere.parentNode.appendChild(newFields);
    // now update it
    container = document.getElementById(newFields.id+counter);
    // Find its child `input` elements
    inputs = container.getElementsByTagName('input');
    selects = container.getElementByTagName('select');
    for (index = 0; index < inputs.length; ++index) {
        // deal with inputs[index] element.
        inputs[index].name =  inputs[index].name + counter;
        inputs[index].value =  inputs[index].name + counter;
    }
    for (index = 0; index < selects.length; ++index) {
        // deal with select element
        selects[index].name = selects[index].name + counter;
        }
 }
window.onload = moreFields;

The Need UPDATED:

Currently, Attempt 2 seems promising but there is something missing. It successfully clones the template, but the procedures to capture the select and input elements is not succeeding.

ORIGINAL:

I'm looking for a solution to patch the already provided for loop to delve deeper, or alternative code that doesn't break the cloning process, but additionally changes the name attributes. All of my attempts to modify this code to traverse deeper have resulted in the code breaking on execution.

This is my first post here, I have found stackoverflow to be incredibly helpful, I hope my problem and its solution can help others learn and understand better. Thanks for assistance in advanced.

like image 262
P.Tedium Avatar asked Nov 01 '22 22:11

P.Tedium


1 Answers

I'm indebted to briansol for helping with the structural example. This code is a functioning solution to my problem. Edits from briansol's original code example includes removal of + counter from the container assignment. Firefox's developer console allowed me to see that the variable was coming up null. Once the counter had been added to the ID, there was no need to append it again.

The Solution

var counter = 0;
function moreFields() {
    counter++;
    var newFields = document.getElementById('poptemplate').cloneNode(true);
    newFields.id = newFields.id+counter;
    newFields.style.display = 'block';
    var insertHere = document.getElementById('catidtable');
    insertHere.parentNode.appendChild(newFields);
    // now update it
    var index, inputs, selects, container;
    container = document.getElementById(newFields.id);
    // Find its child `input` elements
    inputs = container.getElementsByTagName('input');
    selects = container.getElementsByTagName('select');
    for (index = 0; index < inputs.length; ++index) {
        // deal with inputs[index] element.
        inputs[index].name =  inputs[index].name + counter;
    }
    for (index = 0; index < selects.length; ++index) {
        // deal with select element
        selects[index].name = selects[index].name + counter;
        }
}
window.onload = moreFields;
like image 56
P.Tedium Avatar answered Nov 12 '22 11:11

P.Tedium