Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add (clone) form fields using jQuery and increment ids and names

Since it took me a couple of days in order to find a good way to achieve what I wanted, I thought I'd post this Q&A to save others some precious time and unhealthy frustration :3. I simplified the code as much as I could (like removing form action, etc.).

Basically, what I wanted to do is make this :

<form>
    <p>
        <input type="button" value="Add phone number"> 
    </p>
</form>

become this (by clicking on the button) :

<form>
    <div>
        <p>
            Phone number : <input type="text" name="phone_number1"> 
            <input type="button" id="remove_phone_number1" value="Remove">
        </p>
    </div>
    <p>
        <input type="button" value="Add phone number">
    </p>
</form>

and, if I click one more time, it would become this :

<form>
    <div>
        <p>
            Phone number : <input type="text" name="phone_number1"> 
            <input type="button" id="remove_phone_number1" value="Remove">
        </p>
    </div>
    <div>
        <p>
            Phone number : <input type="text" name="phone_number2"> 
            <input type="button" id="remove_phone_number2" value="Remove">
        </p>
    </div>
    <p>
        <input type="button" value="Add phone number">
    </p>
</form>

(all that with a working Remove button, of course)

I thought doing such a thing was pretty straightforward and easy, but I had a really hard time finding a solution.

like image 609
Fierceblood Avatar asked Oct 24 '13 22:10

Fierceblood


2 Answers

Here's what I did! =D

Since I have many pages that are using the same dynamically added form fields, I wanted to be able to include (php) an invisible model of the form in every pages that require it and clone a (or many) visible version of it as needed. I'm not gonna bother you with php includes since it's not what this post is about. Just keep in mind that it's a possible way of reusing my code. Let's dive in!

HTML

<div id="phone_number_form" class="hidden">
    <p>
        Phone number : <input type="text" name="phone_number"> 
        <input type="button" id="remove_phone_number" value="Remove">
    </p>
</div>
<form>
    <p>
        <input type="button" value="Add phone number" id="add_phone_number">
    </p>
</form>

CSS

.hidden {
    display: none;
}

jQuery

<script>
    $(document).ready(function(){
        //We will be using an unique index number for each new instance of the cloned form
        var phone_number_form_index=0;
        //When the button is clicked (or Enter is pressed while it's selected)
        $("#add_phone_number").click(function(){
            //Increment the unique index cause we are creating a new instance of the form
            phone_number_form_index++;
            //Clone the form and place it just before the button's <p>. Also give its id a unique index
            $(this).parent().before($("#phone_number_form").clone().attr("id","phone_number_form" + phone_number_form_index));
            //Make the clone visible by changing CSS
            $("#phone_number_form" + phone_number_form_index).css("display","inline");
            //For each input fields contained in the cloned form...
            $("#phone_number_form" + phone_number_form_index + " :input").each(function(){
                //Modify the name attribute by adding the index number at the end of it
                $(this).attr("name",$(this).attr("name") + phone_number_form_index);
                //Modify the id attribute by adding the index number at the end of it
                $(this).attr("id",$(this).attr("id") + phone_number_form_index);
            });
            //When the Remove button is clicked (or Enter is pressed while it's selected)
            $("#remove_phone_number" + phone_number_form_index).click(function(){
                //Remove the whole cloned div
                $(this).closest("div").remove();
            });
        }); 
    });
</script>

Here's a working example : http://jsfiddle.net/wc28f/3/

I hope my post will help some of you! ^_^

If you find any mistake or possible optimization, please comment and I'll fix them asap

Fierceblood

like image 75
Fierceblood Avatar answered Sep 21 '22 00:09

Fierceblood


I couldn't find a reasonable, flexible solution for a similar problem so I came up with this:

I created an 'original' element and hid it on the page. I appended "---" to the value of any attribute that needed to be incremented within any child elements of the original.

Whenever the user clicked a button to create a clone of the original, I created a clone, then globally replaced "---" with the current index within that clone's HTML. Something like this:

var $clone = $original.clone();
var cloneHTML = $clone.html().replace(/---/g, incrementedFieldNum);
$clone.html(cloneHTML);

// Insert and show the clone after the original
$original.after($clone);

I used a data attribute to store updated values of incrementedFieldNum (not shown in the code above).

Hopefully that helps. It's a lot less code and it's a more general solution I think. I had a lot of nested elements that needed to have incremented IDs and names, so a solution like the one from @Fierceblood was impractical.

like image 39
bergie3000 Avatar answered Sep 19 '22 00:09

bergie3000