Twitter: raymondcamden


Address: Lafayette, LA, USA

Using jQuery to add form fields

02-19-2009 52,020 views Development, jQuery 74 Comments

A reader on another post asked me about using jQuery to dynamically add form fields to an existing form. I whipped up a quick demo that I'd like to get folks opinions on. Here is what I came up with:

view plain print about
1<cfif not structIsEmpty(form)>
2    <cfdump var="#form#">
3</cfif>
4
5<html>
6
7<head>
8<script src="/jquery/jquery.js"></script>
9<script>
10var current = 1;
11
12function addPerson() {
13    console.log('running addPerson')
14    //current keeps track of how many people we have.
15    current++;
16    var strToAdd = '<p><label for="firstname"'+current+'">Name</label> <em>*</em><input id="firstname'+current+'" name="firstname'+current+'" size="25" /> <input id="lastname'+current+'" name="lastname'+current+'" size="25" />'
17    strToAdd += '<p><label for="email'+current+'">Email</label>    <em>*</em><input id="email'+current+'" name="email'+current+'" size="25" /></p>'
18    console.log(strToAdd)
19    $('#mainField').append(strToAdd)
20}
21
22$(document).ready(function(){
23    $('#addPerson').click(addPerson)
24});
25</script>
26</head>
27
28<body>
29
30<form id="someform" method="post">
31    <fieldset id="mainField">
32        <p>
33        <label for="firstname1">Name</label>
34        <em>*</em><input id="firstname1" name="firstname1" size="25" /> <input id="lastname1" name="lastname1" size="25" />
35        </p>
36        <p>
37        <label for="email1">Email</label>
38        <em>*</em><input id="email1" name="email1" size="25" />
39        </p>
40    </fieldset>
41    
42    <p>
43    <input type="button" id="addPerson" value="Add Another Person">
44    </p>
45    
46    <input type="submit" value="Save">
47</form>
48
49</body>
50</html>

I want to talk about this from the bottom up, so please read 'up' with me. The form contains one block of detail for a person - a firstname, lastname, and email address. There are two buttons - one to add another person and one to submit. This is what I started off with as the base form. I wanted it so that when you clicked Add Another Person, it would essentially duplicate the 3 fields.

I began by telling jQuery to monitor the click event for the button (inobtrusive JS FTW):

view plain print about
1$(document).ready(function(){
2    $('#addPerson').click(addPerson)
3});

addPerson then had to do two things. First, it needed to know how many people existed on the page already. I had created a JavaScript variable, 'current', with a hard coded value of 1. This doesn't need to be hard coded, but it certainly seemed to be the simplest way to handle it. Inside of addPerson, I immediately increase the value by one. I generate the HTML I want to use which was basically a cut and paste of the HTML below. The only difference is that I make the number part dynamic. I could have probably used a special character like $N and then used Regex to replace it. (On second though, that would have been a lot cleaner I think.) Then I just append the new string to the HTML.

You can view this here.

So a few open questions/things to discuss:

1) jQuery provides a clone() function for the DOM. In theory, I could have just cloned my fieldset. The problem with that (as far as I know) is that I'd end up with form fields that have the same name. That "works" in CF, but the values would be a list. So for example, form.firstname would be "Ray,Jay". That works well until someone has a comma in their name. Not very likely, but still. I believe in PHP it actually gives you the values in an array, but in CF we have no control over that. Maybe I could have done a clone, gotten the new node, and did the regex on the HTML?

2) I didn't demonstrate the CF side to parse this because I've done so many times before, but in case folks are curious - you would simply introspect the Form struct to figure out how many people you have to process.

3) Of course, the next step is to add validation. I'm willing to bet I can use the kick butt jQuery Validation plugin with dynamic forms. I'll check that next!

 

Related Blog Entries

74 Comments

  • Commented on 02-19-2009 at 12:10 PM
    I've never been a fan of adding elements to the dom via strings of html. I much prefer the createElement approach. I find it to be better practice.
  • Commented on 02-19-2009 at 12:14 PM
    Once you use the jQuery clone() function to clone a node, you can then use the attr() function on the clone element/elements to change the name or ID.
  • Neil Bailey #
    Commented on 02-19-2009 at 12:15 PM
    Ray, when I check out your test, and click the 'add' button, I get 'console not defined' JS error.

    That being said, I have checked out jQuery based solely on the exuberance you have displayed about it in your blog posts.

    I am amazed at its versatility! While I can't say its exactly easy to use, the jQuery mailing list is EXTREMELY responsive and helpful, and I can see us using this in our site in the very near future.

    We are still using CF7 (it works for us, and mgmt feels if it ain't broke....), and are using AjaxCFC for our AJAX calls, and jQuery makes using Rob's package SO much easier.

    So, thanks for pointing us in the right direction. Again.

    And fix your test page :)
  • Commented on 02-19-2009 at 12:31 PM
    @NB: I removed the console messages. How dare you surf w/o Firebug installed? ;)

    @Kyle: It seems like for my use here, adding about 3 form fields, labels, etc, that adding by createElement would be somewhat slow (not slow to run, slow to write)

    @Brian - do you know if clone will return the 'package'? Ie, I clone the fieldSet and get back X, X being the copy of the fieldSet so I could then dig into it and make the changes. Does that make sense?
  • Commented on 02-19-2009 at 12:38 PM
    i've used clone() before. one caveat, if you have the text fields populated and then use clone, the value text also gets cloned so you have to then use jquery to clear out the values of the new form elements as well.
  • Josh Nathanson #
    Commented on 02-19-2009 at 12:46 PM
    Ray - what I've done before is keep a "blank" fieldset that is hidden (display:none) that I can clone as needed - it serves as a "template" for added fieldsets. This way you don't have to worry about picking up data from fields that have been filled already (which could happen if you cloned your onscreen fields). Then use the field renaming process that Brian mentioned in your addperson function.

    This hidden fieldset can be outside the form tags so you don't have to worry about it when you post.
  • Commented on 02-19-2009 at 12:55 PM
    @Josh: That's sexy. I'm going to try that. I'm still wondering though - my q to Brian - do we get a pointer back to the new 'block'?
  • Josh Nathanson #
    Commented on 02-19-2009 at 1:00 PM
    Yeah you do get the pointer back to the new block -- it might look something like this in your addPerson function:

    var newset = $("#hiddenFieldset").clone();
    $("input[name=firstname]", newset).attr("name", "firstname"+current);
    etc.
  • Commented on 02-19-2009 at 1:12 PM
    While a template inside a fieldset outside of the form works, I'm surprised that jQuery doesn't have a native templating system. Prototype.js can create a template with something like:

    var template = new Template('<input type="text" name="field#{number}" value="" /><br /');

    And then to add it you would call:

    new Insertion(
    'bottom': template.evaluate({number: currentCount++});
    );
  • Commented on 02-19-2009 at 1:26 PM
    @Ray: Sorry to be late in responding--stepped away from the computer for awhile.

    But Josh gave you pretty much the same answers I would have. I also tend to use a blank, hidden "template" element to use with the clone() function, then alter the newly cloned element as needed.
  • Emilie #
    Commented on 02-19-2009 at 1:45 PM
    Ray -

    Joern's Validation plugin includes a template utility that will replace {n} placeholders with arguments. This demo makes use of it: http://jquery.bassistance.de/validate/demo/dynamic...
  • Commented on 02-19-2009 at 1:54 PM
    @Brian/Josh - Ok, I'll do an update using clone. SHould be cleaner.

    @Emilie: Interesting. I used that in one of my demos. I'm going to avoid that for now though - I want to do this stuff in baby steps. So my first step is to improve the process w/ clone. Then I'll add the validation. Of course, if I clone, I want need the templating stuff anyway since I'll just use DOM manipulation on the new node.

    Of course... now that I think about it - I will have to do about 6 DOM calls (changing IDs, NAMEs), so it may make sense to NOT use DOM manipulation. Templating may be quicker. But that has the side effect of me needing to update the string if I change the main 'package' I have to clone. Then again, that would also apply to DOM as well.

    Confusing! Ok, I'll take it easy at first and try clone next.
  • Commented on 02-19-2009 at 2:04 PM
    I put together an example of using a Prototype Template if any one is interested:

    http://www.jonhartmann.com/index.cfm/2009/2/19/Exa...
  • Commented on 02-19-2009 at 2:35 PM
    I got to admit - I find that a bit hard to follow. I'll have to read it a few times. (I haven't looked at Prototype in ages.)
  • Commented on 02-19-2009 at 4:30 PM
    I didn't read the comments so i'm not sure if anyone mentioned that the validation plugin already has this built in. The way it works is that you create a "template" which is the form fields that you want to create new rows from which is hidden. Here's the link to the authors site:

    http://bassistance.de/jquery-plugins/
  • Commented on 02-19-2009 at 4:49 PM
    I knew that he had a template style thing - but - I thought it was primarily for error templates, ie, so you could make a generic error: You must type {1} characters, and his code would replace {N} with the right value. I wasn't aware of the use in generating new form fields. I'll have to dig.
  • Commented on 02-19-2009 at 4:50 PM
    @Ray: I took your demo and reworked it to use cloning based on a template (much like Josh described in his earlier comment) using just jQuery.

    I wrote it such that you don't have to update each "for", "name", and "id" attribute individually. You can see it/view the code for it here:

    http://www.swartzfager.org/blog/demoFiles/clonedFi...
  • Commented on 02-19-2009 at 5:53 PM
    Not sure if you were skipping it for examples sake, but you're lacking a formal controller setup for you scripts (which might have been part of the confusing when looking at my example). I just finished a post about JS controllers on my page: http://www.jonhartmann.com/index.cfm/2009/2/19/Evo...
    That might help dispel some of the confusion about my example.
  • Commented on 02-19-2009 at 8:03 PM
    @Brian: I noticed that you disabled the form submit. If you had not, and you submitted, would those hidden form fields get posted as well? I guess it isn't a big deal, you could ignore them.
  • Commented on 02-19-2009 at 8:48 PM
    @Ray: Yes, the hidden template fields would be submitted as well, so you'd have to program your server-side code to only process the field names ending in numerals. Another alternative would be to put the template outside of the form (or in another form) so it's not part of the form submission.

    If the form submission was a regular submission and not an AJAX submission, I suppose you could also use the jQuery remove() function on the template after the client-side validation took place and just before the form was submitted, thereby eliminating it from the form submission.
  • Misty #
    Commented on 05-10-2009 at 6:39 AM
    Perfect ray! well Jqury too good. But how can we add the remove link against each newly created textboxes, not in front of first one but other textboxes that are generated dynamically.

    2. how we Limit the textboxes to 10. mean they should not exced more than 10. a Popup alert message should be displayed that no more than 10.
  • Commented on 05-10-2009 at 9:36 PM
    #2 is easy. Just keep a counter of how many times you add an item.

    #1 You would modify the HTML added to include the link. That link would run JS code to remove the item. It would be a bit more complex, a bit too much for a blog comment.
  • Commented on 07-13-2009 at 2:21 PM
    Ok, I think this is a pretty cool way manipulating the form and I'm considering using it. I was wondering if there was a way to use this technique in conjunction with the available built in SpryValidationTextField in Dreamweaver? I'm guessing it's probably not possible because your not actually reloading the form when you add your 'Person'. Any thoughts?
  • Commented on 07-17-2009 at 10:35 PM
    Not sure. It's been a while since I used Spry Validation, but I don't remember it as supporting dynamic validation on the fly.
  • Commented on 07-25-2009 at 9:49 PM
    I made a similar article that deals with the dynamically added fields slightly better way (imo) using an array - E.g. 'field[]'. You can then loop through them as an associtaive array using php. I recently wrote an article about this on my blog - http://www.web-design-talk.co.uk/58/adding-unlimit... - I also deal with saving these dynamic values to a database using a many-many data structure.
  • Commented on 07-25-2009 at 9:56 PM
    Interesting. CF won't deal nicely with foo[]. If you repeat a form field in CF, then CF will give you one list of values. This means that if one value has a comma in it, you won't be able to tell what the real set of values were.
  • Commented on 07-29-2009 at 7:18 PM
    Hello!

    I was tweaking around with the code a bit, trying to get it to work with something Im working on and for some reason I can't get it to work in IE. Can anyone point out why?

    http://pastebin.com/m5c9478a1
  • Commented on 07-29-2009 at 7:19 PM
    I hate to double post like some forum newb but I also wanted to state that when I try to execute my code in IE, its giving an error and says that the error is because "console" is undefined... Any help is greatly appreciated
  • Michael Appenzellar #
    Commented on 09-11-2009 at 9:30 PM
    I got this working, but 2 things I am running into. Ideally I want to be able to utilize a link vs a button to generate these new fields...this possible? Also, this seems weird, but if I have the button in the table close to the fieldset tag, it doesn't work, but if I move the button further down, it works..its almost like it think it doesn't have room to grow..I know, sounds weird.
  • Commented on 09-12-2009 at 8:32 AM
    Yes, you can use a link instead of a button. It is important though that the handler for it use return false to stop the normal action of a link to try to go someplace.

    As for the button - not sure. I'd have to see it to help.
  • Michael Appenzellar #
    Commented on 09-12-2009 at 10:23 PM
    well I thought I would be able to show an example but now its being weird ;o) What I want to do is say I have a form with a table. I have a row that has say qty, title, total all with textboxes in a row. Below that row I want to have a +Add New LINK which will dynamically create a new table row with text td's and textboxes for every time I click the +Add New link.
  • Michael Appenzellar #
    Commented on 09-12-2009 at 10:23 PM
    well I thought I would be able to show an example but now its being weird ;o) What I want to do is say I have a form with a table. I have a row that has say qty, title, total all with textboxes in a row. Below that row I want to have a +Add New LINK which will dynamically create a new table row with text td's and textboxes for every time I click the +Add New link.
  • Commented on 09-12-2009 at 10:24 PM
    Here is an example of adding a table row with jQuery: http://stackoverflow.com/questions/171027/jquery-a...
  • Commented on 09-15-2009 at 10:37 AM
    Thanks again Ray. This came in handy for adding multiple days/times for classes in an admin.
  • Commented on 09-15-2009 at 11:23 PM
    Can you think of any reason why the fields would be generated fine with unique names (class1,class2,etc.) but when submitted and form scope is dumped they do not show up in there?
  • Commented on 09-16-2009 at 6:55 AM
    They may be being added after your FORM ends. If you have it online I can take a look.
  • Commented on 09-16-2009 at 8:45 PM
    Finally figured it out. Apparently form fields that are added with jquery are not posted if your opening form tag is contained in an include/template... I put the opening form tag on the same page and it recognized all the form fields added with jquery.
  • Michael Appenzellar #
    Commented on 09-17-2009 at 2:49 PM
    Ok..this works great, but one last small issue. In my form fields I have an action such as onClick, but it doesn't appear to work on these generated form fields. Any idea..or am I just plain crazy..lol
  • Commented on 09-17-2009 at 2:51 PM
    Nope, this is expected. Check out the Live() function:

    http://docs.jquery.com/Events/live
  • Joyrex #
    Commented on 03-03-2010 at 4:52 PM
    This was a great little tutorial - one thing I can't seem to figure out though, is how to set a hidden field with the total number of SETS (not individual fields) added - and by SETS I mean the set of fields cloned from the template outside the FORM used to add more fields. Also, would removing a set (as I did provide a remove button) increment or decrement this value, or is it set at the time of submission? Thanks for any help you can provide!
  • Mitch McBride #
    Commented on 03-03-2010 at 11:18 PM
    @Joyrex: Check out http://www.wdsn.ru/wp-content/examples/clone-examp...
  • Commented on 03-04-2010 at 6:24 AM
    Given a hidden field with id of setcount, and given I use current already as a counter, you can use

    $("#setcount").val(current)
  • Joyrex #
    Commented on 03-04-2010 at 11:18 AM
    Raymond,

    That works great - one problem though - I tried adding it to the removeSet() function to allow users to remove sets they don't need, and it does not decrement the value - I'm still learning JQuery - how would I get a current count of sets created so when I POST the form, I pass on an accurate count? Thanks again for the useful information!
  • Commented on 03-04-2010 at 11:22 AM
    Odd. So what goes wrong? What error do you get? Is it online where I can see?
  • Joyrex #
    Commented on 03-04-2010 at 11:29 AM
    That's the funny thing - no JS error, it just doesn't decrement the value as I expected it would. I can't unfortunately show you the whole working page as it's on an internal dev environment, but here's the JS that creates, and removes, the sets (which are located outside the FORM tags so they don't get POSTed):

    var current= 1;
    $(document).ready(function() {
       $("#addUpload").click(function() {
          current++;
          
          $newUpload= $("#userTemplate").clone(true).removeAttr("id").attr("id", "fieldSet" + current).insertBefore("#userTemplate");
          //$newUpload.children("label").each(function(i) {
    //         var $currentElem= $(this);
    //         $currentElem.attr("for",$currentElem.attr("for")+current);
    //      });
          $newUpload.children("label").children("input").each(function(i) {
             var $currentElem= $(this);
             $currentElem.attr("name",$currentElem.attr("name")+current);
             $currentElem.attr("id",$currentElem.attr("id")+current);
          });
          $newUpload.children("label").children("select").each(function(i) {
             var $currentElem= $(this);
             $currentElem.attr("name",$currentElem.attr("name")+current);
             $currentElem.attr("id",$currentElem.attr("id")+current);
          });
          
          var f = $("#fieldSet"+current);
          f.html(f.html().replace("fieldSetID", "fieldSet"+current));

          $newUpload.appendTo("#mainField");
          $newUpload.removeClass("hideElement");
          $("#setcount").val(current);
          //add validation
          //$("#firstname"+current).rules("add", { required:true,minlength:2 });
    //      $("#lastname"+current).rules("add", { required:true,minlength:2 });
    //      $("#email"+current).rules("add", { required:true,email:true });
    //
       });
       
       //$("#uploadFields").validate({
    //      groups: {
    //         fullname: "firstname1 lastname1"
    //      },
    //      errorPlacement: function(error, element) {
    //          if (element.attr("name") == "firstname1"
    //                   || element.attr("name") == "lastname1" )
    //          error.insertAfter("#lastname1");
    //          else
    //          error.insertAfter(element);
    //       },
    //      rules: {
    //         firstname1: {
    //            required: true,
    //            minlength: 2
    //         }
    //         ,lastname1: {
    //            required: true,
    //            minlength: 2
    //         }
    //         ,email1: {
    //            required: true,
    //            email: true
    //         }
    //      }
    // });
    });

    function removeSet(id) {
       $(id).remove();
       $("#setcount").val(current-1);
    };

    Don't mind the commented out stuff - I'm going to set up the validation once I get the form submitting properly (that's a whole 'nother ball of wax), and this counter being accurate is key to that for the server-side stuff.
  • Commented on 03-04-2010 at 11:33 AM
    So first - be sure to set the hidden form field to visible - it will help. Secondly, I assume the remove works? It's just not the counter working? If so, right before it, add alert(current-1).

    Oh.... wait. I don't think this code will work right. If you have 10 items and remove 2, current is always going to be 10.

    You need a better solution - one that counts the items. Since each item is wrapped in a fieldset, can you give them all one class, and then simply do a $(".theclass").size()? THat code isn't exactly right - I forget how you count the results of a jQuery selector, but you get the idea I hope. You would use the same code both in the add and the subtraction.
  • Joyrex #
    Commented on 03-04-2010 at 11:44 AM
    Raymond,

    Ah - making the field visible helped - it DOES decrement the number on removal, but ONLY the first time - subsequent removals of other sets does not decrement it. Changing the val(current-1); to val(current--) produces very strange behavior - it will ignore the first removal, but then WILL decrement subsequent removals, but will always be 1 more than the number of sets actuall left (add to this there is always an initial set that cannot be removed). Any ideas?
  • Commented on 03-04-2010 at 11:46 AM
    It isn't ignoring the removal.

    x--

    means: Return the current value of X, THEN make it 1 smaller. You want:

    --x

    However, that won't work because the add code assumes current always grows bigger. If it goes down and you add to it, things will break.

    See the end of my last comment.
  • Joyrex #
    Commented on 03-04-2010 at 12:33 PM
    Raymond,

    Your suggestion worked! there was a DIV being wrapped around each set being created, and all that was required was appending the class to all the DIVs created, as well as making a DIV around the initial set with the same class so the add/remove count was accurate. Here's the bits of code that ended up working:

    var n = $(".set").size();
    $("#setcount").val(n);

    This added to the removeSet() function as well decrements it accurately. Thanks so much for your help on this, and hopefully others can benefit from it as well!
  • Commented on 03-04-2010 at 12:35 PM
    .size()! Cool. I always forget that name. Glad you got it working.
  • Joyrex #
    Commented on 07-12-2010 at 11:35 AM
    Raymond,

    It's me again - thanks again for your help in getting my particular issue sorted out back in March, but now I've been tasked to "enhance" this further, and one thing the users want is the last-created set of fields to have their values set to the previously-created set, so they only need to change what's needed, rather than having to duplicate effort for each set of fields each time. I've looked and looked, but couldn't find any examples of where elements cloned could have their values set to a particular set of elements. Any advice/help is appreciated!
  • Commented on 07-12-2010 at 3:33 PM
    Simple. We know the # of the fields we are adding, ie, name10 for example. If you know that, then the previous one is name9. You can get the value using:

    $("#name9").val()

    and then use the result to set the value in 10.
  • Joyrex #
    Commented on 07-12-2010 at 3:53 PM
    I think I understand what you're saying... but when the fieldsets are being added dynamically (and thus I don' t know what the current highest-numbered fieldset is), I'm not quite sure how this would be implemented. Here's the code that creates each input for the set:

    $newUpload.children("label").children("input").each(function(i) {
             var $currentElem= $(this);
             $currentElem.attr("name",$currentElem.attr("name")+current);
             $currentElem.attr("id",$currentElem.attr("id")+current);
          });

    Could I use "current" in place of the ID in your example?

    Thanks again for the quick reply and assistance!
  • Commented on 07-12-2010 at 4:15 PM
    Yeah - current is 10, so current-1 is the last one. jQuery would also let you get a last item and walk backwards too. As expected - there will be multiple ways of doing it.
  • Joyrex #
    Commented on 07-13-2010 at 4:47 PM
    Raymond,

    OK, looks like I don't understand what you mean - I tried this syntax out and no dice... I wish I could wrap my head around jQuery as easily as some seem to do...

    var current= 1;
    $(document).ready(function() {
       $("#addUpload").click(function() {
          current++;

          
          $newUpload= $("#userTemplate").clone(true).removeAttr("id").attr("id", "fieldSet" + current).insertBefore("#userTemplate");
          
          $newUpload.children("label").children("input").each(function(i) {
             var $currentElem= $(this);
             $currentElem.attr("name",$currentElem.attr("name")+current);
             $currentElem.attr("id",$currentElem.attr("id")+current);
             $currentElem.attr("value",$currentElem.attr("id"current-1).val()+current);
          });
          $newUpload.children("label").children("select").each(function(i) {
             var $currentElem= $(this);
             $currentElem.attr("name",$currentElem.attr("name")+current);
             $currentElem.attr("id",$currentElem.attr("id")+current);
             $currentElem.attr("value",$currentElem.attr("id"current-1).val()+current);
          });
          
          var f = $("#fieldSet"+current);
          f.html(f.html().replace("fieldSetID", "fieldSet"+current));

          $newUpload.appendTo("#mainField").fadeIn(600);
          $newUpload.addClass("set");
          $newUpload.removeClass("hideElement");
          var n = $(".set").size();
          $("#setcount").val(n);
          $('#docDate'+current).dateEntry();
          
          //add validation
          //$("#docType"+current).rules("add", { required:true,minlength:1 });
          $("#xDocUpload"+current).rules("add", { required:true,minlength:1 });
          $("#docDate"+current).rules("add", { required:true,date:true });
          $("#dateCode"+current).rules("add", { required:true,minlength:1});
          $("#sdoc"+current).rules("add", { required:true,minlength:1});
       });
       
       $("#uploadFields").validate({
    //      groups: {
    //         fullname: "firstname1 lastname1"
    //      },
          errorPlacement: function(error, element) {
              //if (element.attr("name") == "firstname1"
    //                   || element.attr("name") == "lastname1" )
    //          error.insertAfter("#lastname1");
    //          else
              error.insertAfter(element);
           },
          rules: {
             //docType1: {
    //            required: true,
    //            minlength: 1
    //         }
             xDocUpload1: {
                required: true,
                minlength: 1
             }
             ,docDate1: {
                required:true,
                date:true
             }
             ,dateCode1: {
                required: true,
                minlength: 1
             }
             ,sdoc1: {
                required: true,
                minlength: 1
             }
             ,MasterDocTypeID: {
                required: true,
                minlength: 1
             }
          }
    });
    });

    function removeSet(id) {
       $(id).fadeOut(600,function(){$(id).remove();});
       var n = $(".set").size();
       $("#setcount").val(n);
    };

    BTW, that's the whole script from my page, for the sake of completeness. I tried looking up the "other ways" I could do it (I looked into using the :last selector, but none of my experiments took me any closer to a solution). Is it Friday yet?
  • Commented on 07-13-2010 at 9:28 PM
    Next time - please use pastebin for large code like this - makes it easier. :)

    I think this is part of your problem:

    $currentElem.attr("value",$currentElem.attr("id"current-1).val()+current);

    specifically:

    .attr("id"current-1)

    That's not valid JS syntax. Try

    .attr("id"+(current-1))
  • Commented on 07-14-2010 at 10:37 PM
    you can refer to this site on how to duplicate fields with the great jQuery plugin. with just a few line of javascript code.

    http://www.ryscript.co.cc/jQuery/jQuery-duplicate-...

    thanks
  • Joyrex #
    Commented on 07-26-2010 at 11:41 AM
    Sorry for the delay in responding - I was on vacation.

    Rys: Duplicating fields is not the issue (the initial example Raymond shows in this posting does an excellent job of that) - what I'm wanting is for the newest set of form fields DATA to be set based on the last set of form field's DATA that has been set by the user, so if they are doing similar (or the same) values on the fields in multiple sets, it saves them time by not having to set the same value over and over for each set they create.

    Raymond: Still not working (the syntax correction you provided DOES work, but it's still not setting the newly created set's field values to the last created set's values). Since the new sets are being created from a hidden "template", does the trigger (for lack of a better term) need to be on each newly created upload set and target the "template", so when the "template" is used, the default values are the same as the last set values of the last-created set? I appreciate the help on this, as this is driving me batty trying to figure out the right way to do this.
  • Joyrex #
    Commented on 07-27-2010 at 11:18 AM
    I managed to figure it out myself - I ended up using the very useful Field plugin (http://www.pengoworks.com/workshop/jquery/field/fi...), and setting an onChange event to the fields in the template, so when a new set was generated from the template and the user changed the values, the template would be updated with those values so the next set retained those values.

    Here's the link to the PasteBin page for the updated code:

    http://pastebin.com/RktDsJxF

    HUGE thanks for Raymond for the original concept/implementation, and everyone else who offered suggestions/ideas!
  • Commented on 07-27-2010 at 8:33 PM
    Glad you got it!
  • Geekie #
    Commented on 07-31-2010 at 2:47 PM
    Is there a way to have a set of predefined options:
    <input type=text" value= "water">
    <input type=text" value= "soda">
    <input type=text" value= "juice">
    that when clicked, are added to the list and then I can just submit them all? I keep thinking this should be so simple but for some reason I can't get it....help - please.
  • geekie #
    Commented on 08-01-2010 at 11:06 AM
    Never mind..... I got it, duh. I was tired yesterday :)
  • Chap #
    Commented on 01-03-2011 at 3:13 PM
    Looking for a suggestions...

    First, my cloning is working great thanks to this post. I don't need help with that. Instead, how would you recommend handling of database updates/inserts?

    My page is looping over data and presenting the data as input fields so the user can make changes and then save the changes at one time. The user needs to be able to add records, too. Let's say the form has 10 rows with each row having 5 fields to update and the new needs to add 3 new records (5 fields per row). I can update the 10 records, no problem, but how do I account for the 3 newly added records of data?

    Note: the 10 rows have a unique id value but they are not necessarily sequential.
  • Joyrex #
    Commented on 01-03-2011 at 4:13 PM
    I can post my processing code... that was actually the more difficult part of my application to create and test, and does similar stuff to what you're doing.

    http://pastebin.com/nEDhfcdB

    Keep in mind it's pretty specific to what I need to do, but the looping and discovery of the dynamically-numerated fields coming in code should give you ideas on how to approach your needs. Good luck!
  • jak #
    Commented on 02-03-2011 at 4:34 AM
    How can I get the appended elements value via php $POST after the form is submitted?

    For example I create an element with name=ex2 by pressing the button. After form submit $
    POST['ex2'] does not exist...

    What am I doing wrong? How can I get the value of the dinamicaly created ements after the form is submitted?
  • Commented on 02-03-2011 at 7:51 AM
    I don't use PHP jak, but it looks like you are passing the variables in the query scope. In ColdFusion, that's the URL scope. I'd assume PHP separates query string variables versus form variables.
  • Commented on 02-03-2011 at 7:53 AM
    I just googled and it looks like it's $_GET instead. To be clear, you should try to use form posts as much as possible, but if you know your data is going to be small, then passing it over the query string should be fine.
  • Commented on 12-20-2011 at 7:05 AM
    Hi this script is great! but how can I make a remove button?

    I have tried this:


    function removePerson() {

    $('#mainField').remove('#form'+current)
    }

    $(document).ready(function(){
    $('#removePerson').click(removePerson)
    });

    but it does not work. any help please? thanks
  • Commented on 12-20-2011 at 8:38 AM
    Well it could be a couple of things.

    First, ensure your click handler is actually running. Add a console.log("Yo!") as the first line in removePerson().

    Then - you need to ensure your remove is working right. You are telling it to remove #formX (where X == current) from within mainField. So perhaps double check that #formX actually matches something:

    var test = $("#form"+current);
    console.log(test.length);
  • Commented on 12-20-2011 at 8:44 AM
    Thanks for the reply. what is console.log? I removed it as it was not working for me. is it a cold fusion bit of code? im running my test site as plain html.

    I will have another look at my code and see if removePerson is actually doing something. thanks.
  • Commented on 12-20-2011 at 8:47 AM
    console is a JavaScript object available to most modern browsers. It originally came from the Firebug extension for Firefox. It's essentially a way to debug in JavaScript. Google a bit for some demos of it.
  • Commented on 12-20-2011 at 8:52 AM
    Sorry just tried what you said. my functioned works I got a Yo back but when I tested the "form+current+" I got 0 so I guess that means false it does not exist.

    Here is the full code if it helps thanks.

    <html>
    <head>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1...;
    <script>
    var current = 1;

    function addPerson() {

    current++;
    var strToAdd ='<h2 id="form'+current+'">Attendee'+current+'</h2><table><tr><td><label>First Name</label></td><td><input id="firstname'+current+'" name="firstname'+current+'" type="text" /></td><td>Phone:</td><td><input id="phone'+current+'" name="phone'+current+'" type="text" /></td></tr><tr><td>Last Name:</td><td><input id="lastname'+current+'" name="lastname'+current+'" type="text" /></td><td>Company:</td><td><input id="company'+current+'" name="company'+current+'" type="text" /></td></tr><tr><td>Email:</td><td><input id="email'+current+'" name="email'+current+'" type="text" /></td></tr></table>'


    $('#mainField').append(strToAdd)
    } //end add

    function removePerson() {
    // alert("yo!");
    $('#mainField').remove('#form '+current+)
    }

    $(document).ready(function(){
    $('#addPerson').click(addPerson)
    });

    $(document).ready(function(){
    $('#removePerson').click(removePerson)
    });

    var test = $("#form"+current);
    alert(test.length);


    </script>
    </head>

    <body>

    <form id="someform" method="post" action="">
    <fieldset id="mainField">
    <h2>Attendee</h2>
    <table>
    <tr>
    <td>First Name</td>

    <td><input id="firstname1" name="firstname1" type="text" /></td>

    <td>Phone:</td>

    <td><input id="phone1" name="phone1" type="text" /></td>
    </tr>
    <tr>
    <td>Last Name:</td>

    <td><input id="lastname1" name="lastname1" type="text" /></td>

    <td>Company:</td>

    <td><input id="company1" name="company1" type="text" /></td>
    </tr>
    <tr>
    <td>Email:</td>

    <td><input id="email1" name="email1" type="text" /></td>
    </tr>
    </table>
    </fieldset>

    <p>
    <input type="button" id="addPerson" value="Add Another Person">

    <input type="button" id="removePerson" value="Remove Person">

    </p>

    <input type="submit" value="Post">
    </form>

    </body>
    </html>
  • Commented on 12-20-2011 at 9:08 AM
    In the future, please use Pastebin to paste large blocks of code.

    First off, this looks wrong: $('#mainField').remove('#form '+current+)

    Notice the + at the end. That's not valid JavaScript.

    Secondly, you put those 2 test statements by themselves. They should be after the alert('yo')
  • Commented on 04-19-2014 at 9:16 AM
    This one is a nice and useful tutorial.
    You might want to take a look at this jquery version to do the same thing http://voidtricks.com/jquery-add-remove-input-fiel...

Post Reply

Please refrain from posting large blocks of code as a comment. Use Pastebin or Gists instead. Text wrapped in asterisks (*) will be bold and text wrapped in underscores (_) will be italicized.

Leave this field empty