17
Sep
2009

You know the situation. You have a form with 'x' number of text inputs. Eventually, you realize 'x' may not be enough for all users. But in the interest of keeping the page clean, you don't want to arbitrarily continue to add these elements.

What you really want to do is show a minimal amount initially, and then give the user the option of adding as many more (within reason) as that particular user might need. You might go about doing that by creating 100 fields and setting their CSS display attribute to "none", while adding a slick JavaScript function to allow the user to display as many as they need. And that would work, but...

Why create any DOM elements that aren't going to be used? Wouldn't it be better to dynamically create an element and add it to the DOM as the user needs it? (Hopefully you're nodding in affirmation) Great! Let's do it with jQuery.

First, you'll want to see it in action. I've put together a quick demo for you to check out. The rules of the demo are simple. You can add up to 5 names, and you must have at least one. Take a look and c'mon back so we can walk through the code.

Let's take a look at the code first, and then break it down. As with previous entries, you can copy and paste this code onto your own machine and run it, since it points to Google for the jQuery core files. Also be aware that the jQuery code is much leaner than what you see. Almost half of the lines of code are comments for your benefit.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
                    "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
	<title></title>
	<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js"></script>

	<script type="text/javascript">
		$(document).ready(function() {
			$('#btnAdd').click(function() {
				var num		= $('.clonedInput').length;	// how many "duplicatable" input fields we currently have
				var newNum	= new Number(num + 1);		// the numeric ID of the new input field being added

				// create the new element via clone(), and manipulate it's ID using newNum value
				var newElem = $('#input' + num).clone().attr('id', 'input' + newNum);

				// manipulate the name/id values of the input inside the new element
				newElem.children(':first').attr('id', 'name' + newNum).attr('name', 'name' + newNum);

				// insert the new element after the last "duplicatable" input field
				$('#input' + num).after(newElem);

				// enable the "remove" button
				$('#btnDel').attr('disabled','');

				// business rule: you can only add 5 names
				if (newNum == 5)
					$('#btnAdd').attr('disabled','disabled');
			});

			$('#btnDel').click(function() {
				var num	= $('.clonedInput').length;	// how many "duplicatable" input fields we currently have
				$('#input' + num).remove();		// remove the last element

				// enable the "add" button
				$('#btnAdd').attr('disabled','');

				// if only one element remains, disable the "remove" button
				if (num-1 == 1)
					$('#btnDel').attr('disabled','disabled');
			});

			$('#btnDel').attr('disabled','disabled');
		});
	</script>
</head>

<body>

<form id="myForm">
	<div id="input1" style="margin-bottom:4px;" class="clonedInput">
		Name: <input type="text" name="name1" id="name1" />
	</div>

	<div>
		<input type="button" id="btnAdd" value="add another name" />
		<input type="button" id="btnDel" value="remove name" />
	</div>
</form>

</body>
</html>

The Markup

Let's look at what's going on, starting with the form itself:

<form id="myForm">
	<div id="input1" style="margin-bottom:4px;" class="clonedInput">
		Name: <input type="text" name="name1" id="name1" />
	</div>

	<div>
		<input type="button" id="btnAdd" value="add another name" />
		<input type="button" id="btnDel" value="remove name" />
	</div>
</form>

Very straightforward markup. A single form with an "id" attribute. The form contains a div holding a text input and some label text. The div is assigned a class of "clonedInput". This is important. The name can be whatever you choose, but the fact that there is a particular class assigned to this div will be used in our jQuery code.

Next up is another div that holds 2 button elements, each with a unique id attribute. As you might have guessed, on click, one will add a new form element, and the other will remove a form element.

That's it for our markup. And therein lies the true beauty of jQuery. Our markup is clean and pristine. No need to litter it with hidden elements that we may not even need.

jQuery - The First Step

Moving to the jQuery code itself. Starting off very basic, the first thing we're going to do is disable the "remove name" button. Since the page initially renders with only one name field, we don't want to let the user remove that.

$(document).ready(function() {
	$('#btnDel').attr('disabled','disabled');
}

At it's most basic, jQuery adheres to the principle of "find something, do something". Right now, we're finding the element with the id "btnDel", and what we're doing with it is setting it's "disabled" attribute to "disabled".

jQuery - Adding a New Form Element

Next we're going to want to handle the click event for the "btnAdd" button:

$(document).ready(function() {
	$('#btnDel').attr('disabled','disabled');

	$('#btnAdd').click(function() {
		var num		= $('.clonedInput').length;	// how many "duplicatable" input fields we currently have
		var newNum	= new Number(num + 1);		// the numeric ID of the new input field being added

		// create the new element via clone(), and manipulate it's ID using newNum value
		var newElem = $('#input' + num).clone().attr('id', 'input' + newNum);

		// manipulate the name/id values of the input inside the new element
		newElem.children(':first').attr('id', 'name' + newNum).attr('name', 'name' + newNum);

		// insert the new element after the last "duplicatable" input field
		$('#input' + num).after(newElem);

		// enable the "remove" button
		$('#btnDel').attr('disabled','');

		// business rule: you can only add 5 names
		if (newNum == 5)
			$('#btnAdd').attr('disabled','disabled');
	});
}

Still using the "find something, do something" principle, but this time, once we find the element (in this case, the element with the id "btnAdd"), we're going to listen for a specific event (in this case, the click event), before we do something (in this case, create a new element and append it to the DOM).

var num	    = $('.clonedInput').length;
var newNum  = new Number(num + 1);
var newElem = $('#input' + num).clone().attr('id', 'input' + newNum);

First we're going to set a few variables:

  1. Using a jQuery selector, we're going to look for all elements with the class of "clonedInput" (remember this was the class assigned to the div that held the actual form element). jQuery returns an array of matching elements. We need to know how many there currently are, so we access the array's length property.
  2. The variable newNum is going to refer to the next element... the one we're going to create. So we increment the previous variable (num) by one.
  3. The variable newElem is a reference to a DOM element that we're going to create using jQuery's built in clone() method. Again, using a selector and the "find something, do something" principle, we're going to find the last of the clone-able inputs. As we only have one to start, its id (and name) attribute is "input1". We concatenate the variable num (created in item 1 above) to access that specific element. We clone() it, and then using method chaining, set its id attribute to be "input2" (subsequent elements would be "input3", "input4", and "input5").

Now that we've got our new <div> (complete with a unique ID), we need to manipulate the "name" and "id" attributes of the <input> within.

newElem.children(':first').attr('id', 'name' + newNum).attr('name', 'name' + newNum);

Remember that "newElem" refers to our newly created DOM element. It's a div that contains an input. The input is the first "child" element of the div, so it can be referenced via:

newElem.children(':first');

Next, we want to set the "id" attribute and "name" attribute. Recall that with the first text input, these attributes had the same value ("name1"). Using the "newNum" variable that was set above, we can easily set the "id" and "name" attributes of our new element to "name2".

Again, we're using method chaining. The script block above could have been written as:

newElem.children(':first').attr('id', 'name' + newNum);
newElem.children(':first').attr('name', 'name' + newNum);

But that's not quite as efficient as method chaining, and also a little more verbose. Chained methods do not have to be on the same line, and for the sake of legibility can be written as:

newElem.children(':first')
	.attr('id', 'name' + newNum)
	.attr('name', 'name' + newNum);

Now that we have our new element all set up, we need to insert it into the DOM. As of yet, it's not part of the page, it's just a jQuery variable.

$('#input' + num).after(newElem);

Remember that "num" refers to the current number of clone-able elements. If there's only one element on the page, num equals 1. Using a jQuery selector, we reference the last input, and using the appropriately named jQuery method after(), insert our new element (newElem) into the DOM.

Just 2 more steps and we're done with adding an element.

Because we just added a new element, we know for a fact that we have more than one. So we can now enable the "remove name" button. The first line of jQuery that we wrote today disabled it by setting the "disabled" attribute to "disabled". We just undo that by setting the value to an empty string.

$('#btnDel').attr('disabled','');

Finally, we need to enforce our business rule of ensuring a maximum of 5 elements.

if (newNum == 5)
	$('#btnAdd').attr('disabled','disabled');

Hopefully, you see what happened there. If the value of newNum (the variable representing the newly added DOM element) is 5, disable the "add another name" button. This is identical to disabling the "remove name" button, except for the selector.

jQuery - Removing a Form Element

Good news. We're halfway there. We can now add (up to 5) elements dynamically. But we need to allow the user to remove any elements that they added as well.

$('#btnDel').click(function() {
	var num	= $('.clonedInput').length;	// how many "duplicatable" input fields we currently have
	$('#input' + num).remove();		// remove the last element

	// enable the "add" button
	$('#btnAdd').attr('disabled','');

	// if only one element remains, disable the "remove" button
	if (num-1 == 1)
		$('#btnDel').attr('disabled','disabled');
});

To add a new element, we started out by listening for a click event on the element with the ID "btnAdd". Now, we're going to listen for a click event on the element with the ID "btnDel". Also similar to above, we want to start out by getting the total number of "clonedInput" elements:

var num	= $('.clonedInput').length;

And now that we know how many there are, we can safely remove the last one. jQuery makes this easy by providing a built-in remove() method:

$('#input' + num).remove();

Since we've just removed an element, we're guaranteed to have fewer than the 5 specified as the maximum. We can therefore safely make sure the "add another name" button is enabled:

$('#btnAdd').attr('disabled','');

Finally (yes, I know it's been a long time coming), we need to disable the "remove name" button if only one element remains:

if (num-1 == 1)
	$('#btnDel').attr('disabled','disabled');

Putting it all Together (One More Time)

That's it. If you've stuck with me this far, more power to you. I know it might seem complex, but if you take the time to really look at each line you'll see how straightforward it is. This entry ran a bit longer than I had anticipated, but I wanted to make sure to explain what was happening on a line-by-line basis. In reality, without comments "cluttering" the script, we're talking about under 20 lines of jQuery. Here it is again, the entire page, without comments. Hopefully that will help illustrate that it really is a pretty concise way of handling the need to dynamically add or remove elements from the DOM. Take another look and see if it isn't more clear than it was when you first looked at it above.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
                    "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
	<title></title>
	<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js"></script>

	<script type="text/javascript">
		$(document).ready(function() {
			$('#btnAdd').click(function() {
				var num		= $('.clonedInput').length;
				var newNum	= new Number(num + 1);

				var newElem = $('#input' + num).clone().attr('id', 'input' + newNum);
	
				newElem.children(':first').attr('id', 'name' + newNum).attr('name', 'name' + newNum);
				$('#input' + num).after(newElem);
				$('#btnDel').attr('disabled','');

				if (newNum == 5)
					$('#btnAdd').attr('disabled','disabled');
			});

			$('#btnDel').click(function() {
				var num	= $('.clonedInput').length;

				$('#input' + num).remove();
				$('#btnAdd').attr('disabled','');

				if (num-1 == 1)
					$('#btnDel').attr('disabled','disabled');
			});

			$('#btnDel').attr('disabled','disabled');
		});
	</script>
</head>

<body>

<form id="myForm">
	<div id="input1" style="margin-bottom:4px;" class="clonedInput">
		Name: <input type="text" name="name1" id="name1" />
	</div>

	<div>
		<input type="button" id="btnAdd" value="add another name" />
		<input type="button" id="btnDel" value="remove name" />
	</div>
</form>

</body>
</html>

While I do think it's concise, I also recognize that it might be intimidating when you're new to the jQuery library. If you have questions or comments, please don't hesitate to post them, and I'll do my best to answer.

jQuery concepts used:

Comments (22) | 7283 Views

Comments

Add Comment | Subscribe to Comments

  1. marc esher's Gravatar

    # Posted marc esher on 9/17/09 4:17 PM

    Charlie,
    this seems like one of those posts that a lot of people would look at and no one would comment on because they're starry eyed by your sheer brilliance. Consequently, I want to congratulate you on a fine post.

    Nice code formatting, too! I bet that was a pain to put into your blog, and for your additional attention to such formatting you should be commended.

  2. Charlie Griefer's Gravatar

    # Posted Charlie Griefer on 9/17/09 4:35 PM

    @Marc - heh. thanks :) This entry ended up being longer than I had expected, and I was just worried that it was information overload. Not much point in taking the time to compose a blog entry if folks aren't able to absorb it (and thus learn from it) in one sitting.

    The code formatting is SyntaxHighlighter (http://alexgorbatchev.com/wiki/SyntaxHighlighter). If anyone deserves kudos, it's Alex. He did a great job on it.

  3. TJ Downes's Gravatar

    # Posted TJ Downes on 9/17/09 5:38 PM

    Bookmarked. Good stuff Charlie, thanks!

  4. Mark Mandel's Gravatar

    # Posted Mark Mandel on 9/17/09 9:07 PM

    Is it wrong that I do it this way with jquery (written inline, so typos will exist):
    <cfsavecontent variable="formElem">
    {label}: <input type="text" name="{id}" id="{id}" />
    </cfsavecontent>

    <script type="text/javascript">
    formElemHTML = "#JSStringFormat(formElem)#";

    newElementHTML = formElemHTML.replace(/{label}/ig, "My fancy new label");
    newElementHTML = newElementHTML.replace(/{id}/ig, counter++);

    $("#parentElement").append(newElementHTML);
    </script>

    That's a really lazy showing of it, but you get the gist ;o)

    I just like writing the template in HTML in cfsavecontent, so I don't have to build the DOM node by node.

    Whatcha think?

  5. Charlie Griefer's Gravatar

    # Posted Charlie Griefer on 9/17/09 9:43 PM

    @Mark - Yeah, it's wrong :)

    It's actually a pretty cool approach, and one that I'd not thought of. Always interesting to see a different means to the same end. I'm not sure it's all that much simpler... your 4 lines are equivalent to 5 of mine (so yeah OK, 1 line simpler) :P

  6. GT's Gravatar

    # Posted GT on 9/19/09 6:28 PM

    Hey there Charlie,

    Thanks for this - it provides the foundation for what I'm after. I'm trying to write a 'stock picker' where users can choose their own criteria and then hit 'send' and get the data back.

    I just spent a couple of hours looking for a way to construct a 'multiple filter' on a mySQL database with an interface similar to the e-mail filter function in Thunderbird (or the data filters in Excel or OpenOffice Calc).. simple as pie in design, but getting the functionality to dynamically add new filters was a pain until I found your site.

    Goes to show how important search terms are: I started with "multiple form filters mySQL" and wound up finding the right universe by the time I got to "jquery dynamically add remove elements"; took me eight searches before I even got onto the right track.

    Cheers


    GT

  7. Phil Webb's Gravatar

    # Posted Phil Webb on 9/24/09 12:21 PM

    Charlie,

    First off, amazing code! Very clever. I would like to add multiple text fields in each div. It displays and works correctly but when I submit it only one of the fields comes through correctly. Say the fields are “size” and “color” I get size1, color1, color2, color3, etc.. In other words, the code to rename the name and id only works on one of the fields. You used newElem.children(':first') to access the single field in your example. I assumed I could loop through all the children and use a similar line for each child. The length of the children is only 1, which is confusing. I figured there would be one child for each text box. Any ideas? Thanks!

    Phil

  8. Charlie Griefer's Gravatar

    # Posted Charlie Griefer on 9/24/09 12:29 PM

    @Phil - If your div contains 2 text inputs, there should be 2 children elements. For example, if I have this:

    <div id="myDiv">
       <input type="text" name="text1" id="text1" />
       <input type="text" name="text2" id="text2" />
    </div>

    Then the following jQuery alerts the value '2':

    $(function(){
       alert($('#myDiv').children().length);
    });

    Against the same markup, the following jQuery properly alerts "text1" and then "text2":

    $(function(){
       $('#myDiv').children().each(function() {
          alert($(this).attr('id'));
       })
    });

    Perhaps you're not looping properly?

  9. Phil Webb's Gravatar

    # Posted Phil Webb on 9/24/09 2:11 PM

    Thanks Charlie. I am up and running. I had used children.length instead of children().length to get the length of the children.

    Out of curiosity, is there a way to directly access one of the children without using the .each loop or :first? Something like $('#myDiv').children('foo').attr('id').

  10. Charlie Griefer's Gravatar

    # Posted Charlie Griefer on 9/24/09 2:26 PM

    @Phil - Lots of ways :)

    For example...
    $('#myDiv').children().eq(0) <-- first child
    $('#myDiv').children().eq(1) <-- second child

    I'd suggest looking at:
    http://docs.jquery.com/Selectors
    http://docs.jquery.com/Traversing

    and some really good stuff at:
    http://www.learningjquery.com/2006/11/how-to-get-a...
    http://www.learningjquery.com/2006/12/how-to-get-a...

    If you have a specific situation you're trying to address and need some help, let me know.

  11. Steve Snyder's Gravatar

    # Posted Steve Snyder on 10/8/09 6:19 AM

    Ok. So I understand how this works and I am trying to incorporate it with another script. So far it duplicates the input elements perfectly but I have a script that shows additional information when a Select Option is selected. When you "add another", it works fine however the script that shows the additional info only works on the first. Is there anyway that I can send the number of cloned Div to that script?

    Here's the code:
    <script language="JavaScript" type="text/javascript">

    function getElementsByClass( searchClass, domNode, tagNames) {
       if (domNode == null) domNode = document;
       if (tagNames == null) tagNames = '*';
       var el = new Array();
       var tags = domNode.getElementsByTagName(tagNames);
       var tcl = " "+searchClass+" ";
       for(i=0,j=0; i<tags.length; i++) {
          var test = " " + tags[i].className + " ";
          if (test.indexOf(tcl) != -1)
             el[j++] = tags[i];
       }
       return el;
    }


    function showHide(id)
    {
       // hide every element with class 'tab'
       var tabs = getElementsByClass('hideit');
       for(i=0; i<tabs.length; i++)
          tabs[i].style.display = 'none';
       // hide every element with class 'tab'      

       document.getElementById(id).style.display='block';
       // show element with given tabname
    }


    </SCRIPT>

    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3/jq...;

    <script type="text/javascript">
    $(document).ready(function() {
    $('#btnAdd').click(function() {
    var num = $('.clonedInput').length;
    var newNum = new Number(num + 1);

    var newElem = $('#input' + num).clone().attr('id', 'input' + newNum);

    newElem.children(':first').attr('id', 'name' + newNum).attr('name', 'name' + newNum);
    $('#input' + num).after(newElem);
    $('#btnDel').attr('disabled','');

    if (newNum == 10)
    $('#btnAdd').attr('disabled','disabled');
    });

    $('#btnDel').click(function() {
    var num = $('.clonedInput').length;

    $('#input' + num).remove();
    $('#btnAdd').attr('disabled','');

    if (num-1 == 1)
    $('#btnDel').attr('disabled','disabled');
    });

    $('#btnDel').attr('disabled','disabled');
    });
    </script>



    </head>
    <body>
    <form id="myForm">
    <div id="input1" style="margin-bottom:4px;" class="clonedInput">
    <fieldset>
    <legend>Fabric Type:</legend>
    Select Fabric: <select name="fabrictype1">
    <option value="Booth Buddy" onClick="showHide('boothbuddy1');" />Booth Buddy</option>
    <option value="PopUp (LP Stretch)" onClick="showHide('popup1');" />PopUp (LP Stretch)</option>
    <option value="Retractable Banner Stand" onClick="showHide('bannerstand1');">Retractable Banner Stand</option>
    <option value="Hanging Sign" onClick="showHide('hangingsign1');">Hanging Sign</option>
    <option value="Delta Fabric" onClick="showHide('deltafabric1');">Delta Fabric</option>
    <option value="Table Throw" onClick="showHide('tablethrow1');">Table Throw</option>
    <option value="Table Skirt" onClick="showHide('tableskirt1');">Table Skirt</option>
    <option value="Companion" onClick="showHide('companion1');">Companion</option>
    <option value="Companion 2" onClick="showHide('companion21');">Companion 2</option>
    <option value="Stretch Case Wrap" onClick="showHide('casewrap1');">Stretch Case Wrap</option>
    <option value="Pole Pocket Banner" onClick="showHide('polepocket1');">Pole Pocket Banner</option>
    <option value="Custom" onClick="showHide('custom1');">Custom ...</option>
    </select>
    <div class="hideit 1" id="boothbuddy1" style="display:none;">
    <b>PolySuede - </b><span id="smalltext">Hemmed Edges, Pole pocket top and bottom, Grommets top and bottom.</span>
    </div>

    <div class="hideit 1" id="popup1" style="display:none;">
    <b>PolySuede - </b><span id="smalltext">Hemmed Edges, 2" Velcro sewn to edge.</span>
    </div>

    <div class="hideit 1" id="bannerstand1" style="display:none;">
    <b>Sierra, X-banner, L-Banner - </b><span id="smalltext">Janus - Hotknife Sides, Finished top and bottom.</span>
    </div>

    <div class="hideit 1" id="hangingsign1" style="display:none;">
    <b>Softknit - </b><span id="smalltext">Zipper(s) along top edges, Hemmed where needed</span>
    </div>

    <div class="hideit 1" id="deltafabric1" style="display:none;">
    <b>PolySuede - </b><span id="smalltext">Sewn silicone</span>
    <b>Tripoly - </b><span id="smalltext">Sewn silicone</span>
    </div>

    <div class="hideit 1" id="tablethrow1" style="display:none;">
    <b>PolySuede - </b><span id="smalltext">Hemmed around edges</span>
    <b>Softknit - </b><span id="smalltext">Hemmed around edges</span>
    </div>

    <div class="hideit 1" id="polepocket1" style="display:none;">
    <b>Material - </b><span id="smalltext">PolySuede</span>
    <b>Finishing - </b><span id="smalltext">Hemmed edges, pole pockets</span>
    <b>Specify - </b><span id="smalltext">Pole pocket size or pole diameter</span>
    </div>

    <div class="hideit 1" id="custom1" style="display:none;">
    <b>Material - </b><input type="text" name="fabcmaterial1" /><br />
    <b>Finishing - </b><input type="text" name="fabcfinishing1" /><br />
    <b>Finished - </b><input type="text" name="fabcfinished1" /><br />
    <b>Live Area - </b><input type="text" name="fabclivearea1" /><br />
    <b>Other Information:</b><br />
    <textarea name="fabccomments1" cols="70"></textarea>
    </div>
    </fieldset></div>

    <div>
    <input type="button" id="btnAdd" value="add another name" />
    <input type="button" id="btnDel" value="remove name" />
    </div>

    </form>

  12. J's Gravatar

    # Posted J on 10/10/09 6:52 PM

    Great post. You broke it down to the perfect level. Just what I was looking for.

    Thanks!

  13. Simon Griffee's Gravatar

    # Posted Simon Griffee on 10/13/09 5:42 AM

    Excellent stuff—thank you Charlie!

    One suggestion: Please considering removing the double-dashes in the URL for this post (…jQuery--Dynamically…).

    The double-dashes seem to break an HTML page when the link to this post is placed inside an HTML comment. I discovered this when crediting you for using the above!

    Cheers,
    Simon

  14. Charlie Griefer's Gravatar

    # Posted Charlie Griefer on 10/13/09 10:18 AM

    @Steve Snyder - You'll need to understand what the code is doing, and use appropriate naming conventions. All elements that are duplicated have a "1" after the element name/id. After using jQuery's clone(), you'd need to increment all of those to "2" (then to "3", etc). I worked up some sample code that I can post later on.

    @Simon - Heh. I suppose I can modify that thru the alias in BlogCFC's administrator. In the meantime, how about tinyurl? Either way, thanks for the credit :)

  15. Dan Fish's Gravatar

    # Posted Dan Fish on 10/14/09 7:03 AM

    Great howto. It's really helped a project of mine. I'm still kind of new to this, so I'm probably being dumb, but I'll like to put the remove button next to the added field so users have the option of removing that added line specifically. Any pointers?

  16. Alexia's Gravatar

    # Posted Alexia on 12/21/09 1:57 PM

    Hi!
    Very gooood work! But i have a question for u: How can i use your code and change also THE LABEL of the text box to Name2, Name3 etc...?
    Any ideas?
    Thank you

  17. Sunny's Gravatar

    # Posted Sunny on 1/7/10 3:00 AM

    Thank you so much for this post, I've been looking for a good explanation of dynamic forms with jQuery. I'm so relieved to find just what I needed that I'm going to give a way-too-personal explanation. I'm at a job where web-programming was suddenly thrown onto me even though I'm an electrical engineer. After a month of stressfully trying to work with php I'm somewhat up and running, actually kind of like web-programming. Anyway thanks for making my life easier! I'll buy you a beer if we ever meet :-)

  18. Snyder's Gravatar

    # Posted Snyder on 1/7/10 9:42 AM

    Hey, first of all thanks for the great tutorial. don't know if you check this post anymore, but was wondering how you would validate the newly created input fields just using php. I tried but when I submit and it fails my checks, it loses all the new input elements and I have to re-type everything. I guess I'm asking how you would make the newly created input fields "sticky". I know I could just do jQuery validation, but I want it to be functional without javascript in case someone doesn't have it enabled. food for thought. Thanks!

  19. Ivan Ribakov's Gravatar

    # Posted Ivan Ribakov on 1/25/10 3:06 PM

    Hi, thanks for the code - i modified it a bit to suit my needs, but faced one problem - the inputs that are created dynamically are not being submitted. This happens only in Firefox, but does work in Chrome and even IE.

    Here's HTML:

    <div id=\"input1\" class=\"clonedInput\">                     
       <label for=\"answer1\" class=\"answer_label\">Answer</label>
       <input type=\"text\" name=\"answer1\" id=\"answer1\" class=\"answer\" />
       <label for=\"answer1pt\" class=\"point_label\">Points</label>
       <input type=\"text\" name=\"answer1pt\" id=\"answer1pt\" class=\"points\" size=\"2\"/>                     
    </div>";

    /*Copied from PHP code that why quotes are backslashed*/

    And your modified JavaScript code:

    $('#btnAddAnswer').click(function() {
    var num      = $('.clonedInput').length;
    var newNum   = num + 1;   
    var newElem = $('#input' + num).clone().attr('id', 'input' + newNum);

       newElem.find(".answer_label").attr('for', 'answer' + newNum);
       newElem.find(".answer").attr('id', 'answer' + newNum).attr('name', 'answer' + newNum).attr('value', '');
       newElem.find(".point_label").attr('for', 'answer' + newNum + 'pt');
       newElem.find(".points").attr('id', 'answer' + newNum + 'pt').attr('name', 'answer' + newNum + 'pt').attr('value', '');
       
    $('#input' + num).after(newElem);
    $('#btnDelAnswer').attr('disabled','');
    if (newNum == 5)
    $('#btnAddAnswer').attr('disabled','disabled');
    });

    Any ideas what i'm doing wrong or what the trouble might be?

    P.S. dont know if it is still relevant, but you can get certain child of an element using this construction:
    newElem.find(":nth-child(1)").attr('for', 'answer' + newNum);

    Thanks in advance!

  20. Kliphten's Gravatar

    # Posted Kliphten on 2/1/10 12:01 PM

    Great post. Question: I used this for multiple image uploads but when I post the data, it doesn't go through? Anybody know if I need to do anything to get this to work? I've tried adding a text field dynamically as well and it didn't work either. Any help would be great!

  21. Gerald's Gravatar

    # Posted Gerald on 2/4/10 10:38 PM

    Great Post,
    I want to know If is it posible to validate the new input generated?

  22. doforumda's Gravatar

    # Posted doforumda on 2/17/10 10:08 PM

    This is a good post i like it but i have some problem with it. i modified your code according to my needs. it is working fine as far as adding new form elements is concern. but the problem arise when i try to submit my data to server side scripting. how can i get all the data that are added to all the dynamic fields in this script. let me give my code to you

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
    "http://www.w3.org/TR/html4/loose.dtd">;
    <html>
    <head>
    <title></title>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3/jq...;

    <script type="text/javascript">
       
    $(document).ready(function() {
       
    $('#btnAdd').click(function() {
       
    var num = $('.clonedInput').length;

    var newNum = new Number(num + 1);

    var newElem = $('#input' + num).clone().attr('id', 'input' + newNum);

    newElem.children(':first').attr('id', 'name' + newNum).attr('name', 'name' + newNum);
    $('#input' + num).after(newElem);
    });
             
    });
    </script>
    <style>
    #myForm div {
       font-size:14px;
       margin-bottom: 10px;
       clear: left;
    }
    #myForm label {
       width: 125px;
       display: block;
       font-size:14px;
       font-weight: bold;
       color: #999;
       float: left;
    }
    #btnAdd {
       margin-left:130px;
    }
    </style>

    </head>

    <body>

    <form id="myForm" method="post" action="process.php">
       <div>
    <label>First Name: </label><input type="text" name="fname" id="fname"><br>
    </div>
    <div>
    <label>Last Name: </label><input type="text" name="lname" id="lname"><br>
    </div>
    <div id="input1" class="clonedInput">
    <label>IM Screen Names:</label>
    <input type="text" name="name1" id="name1" />
    <select name="screenname1" id="screenname1">
    <option value="AIM" selected="selected">AIM</option>
    <option value="gtalk">Google Talk</option>
    <option value="skype">Skype</option>
    <option value="windows live">Windows Live</option>
    <option value="yahoo">Yahoo</option>
    </select><br />
    </div>

    <div>
       <a href="#" id="btnAdd">Add another</a>
    </div>
    <input type="submit" name="submit" value="Submit">
    </form>

    </body>
    </html>

    let me give you server side script too so it will be better to understand it. please modify where am i making mistake

    <?php
    $fname = $_POST['fname'];
    $lname = $_POST['lname'];
    $name1 = $_POST['name1'];
    $screenname1 = $_POST['screenname1'];

    echo $fname."<br>";
    echo $lname."<br>";
    echo $name1."<br>";
    echo $screenname1."<br>";

    ?>

Add Comment