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.
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
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With