Adding successive input fields - best practices?

Discussion in 'Javascript' started by J Y, Mar 28, 2008.

  1. J Y

    J Y Guest

    Hi,

    I'm writing a Rails app that uses some Javascript to allow users to
    click a button to add more input fields to the page. I have the code
    working, but it's very unelegant, with the HTML forms packed into the
    Javascript code.

    I don't want to do any server-side stuff for something this simple.
    I'd like to be able to put most of the HTML somewhere in a hidden div,
    but can't think of a way to make that work, since I need to increment
    the index of the "name" field for each new input field.

    What is the best practice for doing this? Surely not the way I have
    done it.

    A snippet of my code is below.

    function add_new_link_fields(new_count){
    new_fields = '<li><span class="newlink_label">New link:</span><span
    class="field_label">URL:</span><span class="r"><input id="site_url"
    type="text" name="site[' + new_count + ']"/></span></li><li><span
    class="field_label">Title:</span><span class="r"><span
    class="r1"><input id="site_title" type="text" name="site[' + new_count
    + '][title]"/></span><span class="r2">Tags: <input id="site_tag_list"
    type="text" name="site[' + new_count + '][tag_list]"/></span></span></
    li><li><span class="field_label">Description:</span><span
    class="r"><input type="text" id="site_description" name="site[' +
    new_count + '][description]"><span class="controls" id="controls' +
    new_count + '"></span></span></li>';
    saved_values = Form.getElements('ajax_submit_form')
    $('new_link_fields').innerHTML += new_fields
    if (new_count > 1) {
    // Restore saved values
    for (i in saved_values) {
    e = saved_values
    if (e.value && e.type != 'submit') {
    $('ajax_submit_form').elements[e.name].value = e.value
    }
    }

    old_count = new_count - 1;
    $('controls' + old_count).innerHTML = "";
    $('in_place_create_submit_button').value = "Add links";
    }
    $('controls' + new_count).innerHTML = $('controls_source').innerHTML;
    }
     
    J Y, Mar 28, 2008
    #1
    1. Advertisements

  2. J Y

    Tom Cole Guest



    Well assuming you didn't have the forms packed into the javascript
    code:

    <form id="myForm" action="..." method="...">
    <input type="button" onclick="addInput();"/>
    ...
    </form>

    The the javascript:

    function addInput() {
    var form = document.getElementById("myForm");
    var newInput = document.createElement("input");
    newInput.type = "text";
    var newId = "input" + form.elements.length;
    newInput.id = newId;
    newInput.name = newId;
    form.appendChild(newInput);
    }

    This will create new input elements with name and ids of the type
    "inputX" with each new input field being one index larger than the
    previous.

    HTH
    [/QUOTE]
     
    Tom Cole, Mar 28, 2008
    #2
    1. Advertisements

  3. J Y

    J Y Guest



    Thank you! This is exactly what I was looking for... I have been
    programming in Basic, C, PHP, and Rails for close to 10 years now, but
    Javascript is still such a mystery to me. Do you have any sites to
    recommend to me for a crash tutorial in Javascript? I see so many
    pages out there that are more focused on quick copy/paste scripts for
    script kiddies, not programmers.

    Also, your example makes perfect sense to me, but my form is quite a
    bit more complicated. How would I go about incrementing the index on
    a form of this size? Ideally, I'd like to keep the styled form hidden
    in HTML and then only copy/edit its properties in Javascript to keep
    separation between presentation and logic, but I'm having trouble
    figuring out how to navigate the DOM to edit the nodes nested so deep.

    <span id="form_source" style="visibility: hidden; position:
    absolute;">
    <li>
    <span class="newlink_label">New link:</span>
    <span class="field_label">URL:</span>
    <span class="r">
    <input id="site_url" type="text" name="site[0]" /> </span> </li> <li> <span class..."controls0"></span> </span> </li> </span> JY[/QUOTE][/QUOTE]
     
    J Y, Mar 29, 2008
    #3
  4. J Y

    pr Guest

    Yes. And those sites tend to contain some very outdated code too. MDC is
    [...]

    Here's one way of doing it. This script removes and stores an HTML div
    containing your fields, placing it in an object. The object creates a
    reference to any nodes that will require updating later. The object's
    insert() method modifies these nodes using a fresh index number and
    appends a clone of the original div to the container that once held it.

    It is an efficient choice because
    a. it only has to navigate once to the nodes it must update each time
    b. cloneNode() is a heap quicker than createElement().

    ........................

    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
    <html>
    <head><title>inserting html blocks</title>
    <script type="text/javascript">
    var fields;

    function HTMLBlock(el) {
    var instance = 1, elementNames = [], i, item, container;

    /* remove source element */
    container = el.parentNode;
    container.removeChild(el);

    /* cache input elements' name attributes */
    for (i = 0; item =
    el.getElementsByTagName("input").item(i); i++) {
    elementNames = item.getAttributeNode("name");
    }

    /* method to modify and insert a clone of the original element */
    this.insert = function () {
    for (var i = elementNames.length; i--; ) {
    /* replace digits with instance # */
    elementNames.nodeValue =
    elementNames.nodeValue.replace(/\d+/, instance);
    }
    instance++;
    container.appendChild(el.cloneNode(true));
    };
    }

    function createHTMLBlock(id) {
    var d = document, el;

    /* test browser supports the methods we'll be using */
    if (d.getElementById && (el = d.getElementById(id)) &&
    el.getElementsByTagName && el.cloneNode &&
    el.getAttributeNode) {
    /* ... etc. */
    return new HTMLBlock(el); // yes
    }
    return null; // no
    }

    function addHTML() {
    if (fields) {
    fields.insert();
    }
    }
    </script>
    </head>
    <body>
    <p>[content]</p>
    <p><input type="button" onclick="addHTML()"
    value="Add Fields">
    </p>
    <div id="new_link_fields">
    <div id="form_source">
    <!-- span would be illegal for this purpose -->
    <ul> <!-- don't forget one of these -->
    <li>
    <span class="newlink_label">New link:</span>
    <span class="field_label">URL:</span>
    <span class="r">
    <!-- life would be easier if you ditched the array-style
    name attributes and used a suffix. I've left them
    for now -->
    <input type="text" name="site[0]" />
    </span>
    </li>
    <li>
    <span class="field_label">Title:</span>
    <span class="r">
    <span class="r1">
    <!-- mostly you don't need ids _and_ names, so I've
    removed ids -->
    <input type="text" name="site[0][title]" />
    </span>
    <span class="r2">Tags:
    <input type="text" name="site[0][tag_list]" />
    </span>
    </span>
    </li>
    <li>
    <span class="field_label">Description:</span>
    <span class="r">
    <input type="text" name="site[0][description]" />
    <span class="controls"></span>
    </span>
    </li>
    </ul>
    </div>
    </div>
    <script type="text/javascript">
    /* remove the HTML and set up the object down here, before
    anything's displayed */
    fields = createHTMLBlock("form_source");
    </script>
    </body>
    </html>
     
    pr, Mar 31, 2008
    #4
    1. Advertisements

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 (here). After that, you can post your question and our members will help you out.