Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cloning and renaming form elements with jQuery

Tags:

jquery

I am looking for an effective way to either clone/rename or re-create address fields to offer ability to submit multiple addresses on the same page. So with form example like this:

<div id="addresses">
  <div class="address">
    <input type="text" name="address[0].street">
    <input type="text" name="address[0].city">
    <input type="text" name="address[0].zip">
    <input type="text" name="address[0].state">
  </div>
</div>
<a href="" id="add_address">Add address form</a>

From what I can understand there are two options to do that:

  1. Recreate the form field by field and increment the index which is kind of verbose:

    var index = $(".address").length;
    
    $('<`input`>').attr({
    name: 'address[' + index + '].street',
    type: 'text'
    }).appendTo(...);
    
    $('<`input`>').attr({
    name: 'address[' + index + '].city',
    type: 'text'
    }).appendTo(...);
    
    $('<`input`>').attr({
    name: 'address[' + index + '].zip',
    type: 'text'
    }).appendTo(...);
    
    $('<`input`>').attr({
    name: 'address[' + index + '].state',
    type: 'text'
    }).appendTo(...);
    
  2. Clone Existing layer and replace the name in the clone:

    $("div.address").clone().appendTo($("#addresses"));
    

Which one do you recommend using in terms of being more efficient and if its #2 can you please suggest how I would go about search and replacing all occurrences of [0] with [1] ([n]). Thank you.

like image 220
Micor Avatar asked Apr 16 '10 00:04

Micor


1 Answers

In theory, the simplest way would be to clone then change name:

var newaddress= $("#addresses div.address").eq(0).clone();
newaddress.find('input').each(function() {
    this.name= this.name.replace('[0]', '['+i+']');
});
$('#addresses').append(newaddress);

However:

a. jQuery's clone() is a really nasty piece of work. On IE, it serialises the nodes to HTML, processes the HTML string with regex (!) to remove its bodge-job internal ID attributes and then asks the browser to re-parse it. This is one of my least favourite parts of jQuery: it's highly error-prone, loses some information, and is slow (not that speed matters for the quite small job you seem to be doing here).

The browser's native cloneNode(true) method is much better, but you can't really use it if you're doing jQuery stuff because it will copy jQuery's internal ids, potentially confusing its scripting. Ugh. What a mess.

b. When you change an input's name, whether that's by input.name as here or using attr() as in your example, there are issues in IE<=7.

In particular, though it will submit the inputs with the correct control name, they won't be indexed under the right name in the form.elements HTMLCollection (or on form itself, though you shouldn't use that anyway). This isn't necessarily a problem if you are selecting inputs based on IDs or jQuery selectors rather than the old-school HTMLCollection interface. Worse is that radio buttons, if you use any, won't be properly name-grouped.

If this is a concern for you I'm afraid using innerHTML/html() to create the div, as in pst's answer, is your only option. (You can always combine the two, creating using HTML then changing the other attributes and text content using text(), attr(), val() etc. to avoid the usual HTML-escaping problems when you go around sticking text strings into HTML.)

like image 106
bobince Avatar answered Sep 19 '22 04:09

bobince