wForms - Server-side handling of the Repeat Behavior (part 1)

This documentation was updated on June 28th 2005 (fixed code sample)

This post is part of the wForms Documentation. wForms is an open-source javascript library that adds commonly needed behaviors to traditional web forms without the need for any programming skill.

For additional help, visit the wForms forum.

The repeat behavior generates form fields dynamically and this makes the server-side processing a bit more complex than with your usual web form. This is a two parts problem: (1) how to retrieve the submitted information and (2) how to pre-fill a form with a repeated element. This post deals with the first and before we start, here’s a short definition: The ‘repeated element’ refers to the element with the ‘repeat’ class (usually a <div>, a <fieldset> or a <tr>).

The Row Count

The wForms extension generates a hidden ‘row count’ field for each repeated element of the form. The name of the field is derived from the id of the repeated element (and you probably want to set that id attribute if you haven’t done so already).

For instance:

<fieldset id=”someid” class=”repeat” >
… some fields…
</fieldset>

wForms will generates the following markup:
<input type=”hidden” id=”someid-RC” name=”someid-RC” value=”" />

The value of the field is a number indicating the number of time the element has been repeated.

The Row Index suffix

In order to maintain the uniqueness of field names, wForms appends a dash followed by the row index to each repeated field.

Original row: <input type=”text” name=”somename” />
Second row: <input type=”text” name=”somename-2″ />
Third row: <input type=”text” name=”somename-3″ />

The first row is left unchanged. This serves two purposes: First, you don’t have to adopt a specific syntax for field names and second, the form can still be processed normally if javascript was unavailable on the client.

Now, it is important to know that there can be gaps in the sequence. For instance, if the user deletes a row before submitting the form, you’ll end up with:

Original row: <input type=”text” name=”somename” />
Third row: <input type=”text” name=”somename-3″ />

The field named ’somename-2′ is missing. In this situation the row count still indicates 3.
This is by design. It would be rather complicated to adjust the counter and renumber all field names in the browser each time a row is deleted.

In effect, the row count gives the upper bound of the loop and the presence of the field must be tested at each iteration.

PHP Code Sample

Here’s the corresponding code in PHP (from memory, let me know if it has any problem):

<?php
// first value:
$value = $_POST["somename"];
// subsequent values:
if( array_key_exists("someid-RC",$_POST)) {
for($i=2;$i < = (int) $_POST["someid-RC"];$i++) {
if( array_key_exists ("somename-".$i,$_POST)) {
$value = $_POST["somename-".$i];
}
}
}
?>

Code sample updated (see comments below)

You’re welcome to share code samples for different environments, or continue reading: how to prefill a form with a repeated element.

 

Update: Comments are now closed for this post, but you can go to the wForms forum if you have any question or comment. Thanks !

41 Responses to “wForms - Server-side handling of the Repeat Behavior (part 1)”

  1. Kevin Smith Says:

    Have you considered structures like so for repeating fields….

    In python, I’m using formencode to decode form values into values like…

    {’name’: [ {’first’:'tom’,’ ‘last’:’smith’}, {’first’:'chloe’, ‘last’:’smith’} ]

  2. cedsav Says:

    Kevin, I suppose your html didn’t go through the comment system. Please post again using html entities (&lt; and &gt;) for your markup.

  3. Kevin Smith Says:

    Thanks, cedsav.

    Have you considered structures like so for repeating fields….

    <input name=”name-1.first” value=”tom” > <input name=”name-1.last” value=”smith” >
    <input name=”name-2.first” value=”chloe” > <input name=”name-2.last” value=”smith” >

    In python, I’m using formencode to decode form values into values like…

    {’name’: [ {’first’:’tom’,’ ‘last’:’smith’}, {’first’:’chloe’, ‘last’:’smith’} ]

  4. cedsav Says:

    Kevin, thanks for your suggestion. I can see how it simplifies the server-side handling of the form. On the other hand, it is more constraining for the web developer, as he needs to name his fields according to that convention.

    wForms requires no particular naming convention and leaves the original field unchanged. This, in effect, forces the developer to write server-side code that works even when javascript is disabled on the client.

  5. samsmith Says:

    Original row:
    Second row:
    Third row:
    $v){
    do some…
    }
    ?>

  6. Henrique Cintra Says:

    The command:

    for($i=1;$i < (int) $_POST[”someid-RC”];$i++)

    should be replaced by:

    for($i=2;$i <= (int) $_POST[”someid-RC”];$i++)

    The variable $i starting with 2 is good because it’ll never be a “somename-1″ field. The <= instead of < is needed, or the last field will never be reached.

  7. cedsav Says:

    Henrique, you’re right. Thanks for pointing that out, I’ll update the documentation.

  8. cedsav Says:

    samsmith, by the way, your comment didn’t go through. Can you post it again ?

  9. el_vartauy Says:

    i always worked with data grids in mind, so what about:
    <input name=”myRow[0]myField” id=”myRow_0_myField” value=”hello” />
    <input name=”myRow[0]myField2″ id=”myRow_0_myField” value=”hello” />
    <input name=”myRow[1]myField” id=”myRow_0_myField” value=”hello” />
    <input name=”myRow[1]myField2″ id=”myRow_0_myField” value=”hello” />

    so you will receive an array, better for iterate trough rows and fields, with all the info you will need, as number of elements.

    i developed my own framework in a fashion not very common, grid oriented.
    i’ll test your code later, looks interesting…

  10. cedsav Says:

    El_vartauy,
    Thanks for your suggestion. I think the [] characters are invalid in (X)HTML in a name attribute. It still works of course, but I’d rather stick to a standard compliant code. The other point is that, as I said in a comment above, I try to make wForms flexible, so no specific syntax is required in the XHTML.

  11. Ian Welsh Says:

    Hey, very, very nice function. Works very well with server side code, both on submit and write.

    I incorporated it into my form with the simple business logic that all repeated ‘items’ would be entered
    into a single field, using a delimiter to separate. I used ;, but if that does not work given your programming environment,
    or the expectation that ; might be entered by user, you can define a ‘delimit’ string
    of random characters and use that as the parse point. The relevent code is below…sorry that
    I dont have php equivalent….please no angry ASP posts ;)

    Lots of ways to slice this, for instance, I allowed the user to change each entry, but you could just print to page
    the value and assume that if they want to change it, they could just ‘remove’ then add a new one.

    (I hope this works, I ran the code below through a ‘cleaner’ since I wasn’t sure if the code would be allowed without)
    (I can post or forward the actual code if anyone needs it native. It should be convertable into PHP pretty easily)

    ***************************
    Build form for submit:
    (I’ll assume you have a variable, fld, that represents the data in the column where you store the information)
    (fld could also just be some variable you build. Again, ; is my delimiter, could just as well be jije3998t6845hj&U$IUh)

    <table>
    <%
    (Dim fld - already set to column value)
    Dim delimit : delimit = ";"
    Dim doloop : doloop = false

    if fld = "" or (fld <> "" AND InStr(fld,delimit) = 0) then
    doloop = false
    else
    doloop = true
    end if

    if Not doloop then
    %>

    <tr class="repeat">
    <td>
    <select id="fld_unique_name" name="fld_unique_name" class="">
    <option value=""><———– Select ———–></option>
    <option value="Something One">Something One</option>
    <option value="Something Two">Something Two</option>
    <option value="Something Three">Something Three</option>
    </select><br/></td>
    <td></td>
    </tr>

    <%
    else
    Dim i
    Dim RC
    Dim CLS
    Dim arrayFld : arrayFld = Split(fld,delimt)
    for i=0 to UBound(arrayFld)
    RC = "-" & CStr(Eval(i+1))
    CLS = "class=""removeable"""
    if i = 0 then RC = ""
    if i = 0 then CLS = "class=""repeat"""
    %>

    <tr <%=CLS%>>
    <td>
    <select id="fld_unique_name<%=RC%>" name="fld_unique_name<%=RC%>" class="">
    <option value=""<%if arrayFld(i)="" then Reseponse.write " checked"%>><———– Select ———–></option>
    <option value="Something One"<%if arrayFld(i)="Something One" then Reseponse.write " checked"%>>Something One</option>
    <option value="Something Two"<%if arrayFld(i)="Something Two" then Reseponse.write " checked"%>>Something Two</option>
    <option value="Something Three"<%if arrayFld(i)="Something Three" then Reseponse.write " checked"%>>Something Three</option>
    </select><br/></td>
    <td></td>
    </tr>

    <%
    next

    end if
    %>
    </table>

    ***************************
    Code after submit:
    (I assume here that you have an open and updateable recordset, RS)

    (Dim RS ‘as recordset)
    Dim delimit : delimit = ";"
    Dim fld : fld = Request("fld_unique_name")

    if fld = "" then
    RS("fld") = null
    else
    for each item in request.form
    if left(item,len("fld_unique_name"))="fld_unique_name" then fld = fld & delimit & request.form(item)
    next
    RS("fld") = fld
    end if

  12. Allen Says:

    We use Zope for our app server…based on Python.
    For forms we can use this:
    <input type=text name=formFields.username:record:list>

    If I have 3 fields all using the same name I get this returned:

    {’formFields’: {’username’: [’Allen’, ‘Bob’, ‘Fred’]}}

    This will return a dictionary object named ‘fields’ that contains a dictionary named ‘username’ that contains a list of the usernames submitted.
    Looping over this list then eliminates the need to add sequence numbers to the form fields.
    I am sure this will work in other languages but simple to do with Zope.

  13. cedsav Says:

    Ian, thanks for sharing your ASP code. Glad it works well.

    For those who’d like to keep their field name unchanged to benefit from server-side features (php’s [] or Python’s notation, as stated by Allen above), you should be able to do a small modification to wForms:

    Around line 242 in wForms.js you’ll find the following line:

    // Prepare id suffix
    var suffix = “-” + rowCount.toString();

    If you change it to:

    var suffix = “”;

    it should work the way you want but I have not tested it.. so it might turn out to be more complex than that. Let me know if you have any problem with it.

  14. Fabricio Says:

    Hola, actualmente estoy utilizando el formulario para repetir los datos, pero se me presento que necesito realizar una actualizacion de ciertos datos que tengo almacenados en la base de datos, la pregunta es:
    ¿Como cargo el formuario con los datos de la base y poder modificar la informacion con este mismo esquema?

    Desde ya muchas gracias.

  15. cedsav Says:

    Fabricio. Sorry, Yo no hablo espanol.. Are you asking how to populate the form with previously submitted data ?

  16. Fabricio Says:

    Nowadays I am using the form to repeat the information, but now I need to load some fields from the informartion base. ¿How do I load the form with the information of the base, and be able to modify the information with the same scheme?

    Thank yo very much

  17. Fabricio Says:

    tanks, yes i need populate the form with previously submitted data.

  18. Fabricio Says:

    sorry, i know the answer.

    Thank you very much.

  19. Scott Says:

    Cedsav, EXCELLENT little site! I like it. Could you create a simple, example PHP form processor for me? Or if someone else has one I cold snag and play with. I don’t know what I’m doing :)
    I’m getting confused by the repeat function still, and I’ve read everything you have on it twice! My problem is that I’m new to PHP, and I’m new to forms…
    so I’m a little slow… THANKS!

  20. cedsav Says:

    Scott,

    If you just need to retrieve field names and values, here’s a very basic form processor:

    foreach ($_POST as $varname => $varvalue) {
    if(is_array($varvalue))
    echo ” $varname = “.implode(”, “, $varvalue);
    else
    echo ” $varname = $varvalue”;

    But usually, you know the name of a field and you want to retrieve its value, so you just do:

    $value = $_POST[’name_of_the_field’];

    The example in the post shows how to retrieve all the submitted values of a field within a wForms Repeated group.

    Let me know if you need to populate a form with a repeat element, that’s more complicated but I have an example I can post.

  21. Scott Says:

    Yes, I am using the repeat element in my form, if you could post an example for me. Thanks!

  22. Scott Says:

    Hey Cedsav, just wondering if you got my last message. Thanks!

  23. cedsav Says:

    Scott, more information is now available here.

  24. samuel Says:

    wonderful script you have. I would like to incorporate with what I am doing right now
    I have two rows with the class=repeat . I use ASP(VBscript) and would want to post the data to a stored procedure in
    SQL Server. I am working on in right now but I would earnestly appreciate any Ideas that would direct me in the right direction
    especially in the area of catching the posted data when rows are added. thanks in advance

  25. matt Says:

    like scott has said — has anyone done a generic form processing script which will handle the repeat behaviour? i have a form which has a repeat row containing 5 inputs. when the form is submitted i need to generate an email with each row as a separate line in the email. i know how to do this with static rows as i enter the values in by hand, but not with automatically generated rows! can anyone help me?

  26. cedsav Says:

    Matt,

    The code sample in this post shows how to retrieve the values of repeated fields. Creating the email’s body is quite similar to what you would normally do.

    For instance, let’s you have a repeated input called ‘lastname’.
    <div class=”repeat” id=”lastnamerow” >
    <input type=”text” name=”lastname” />
    </div>

    In PHP, you retrieve the value like this:

    $lastname = $_POST[”lastname”];

    To add that info to your email:

    $emailbody .= “Last Name: “. $lastname . “\n”;

    To get subsequent values for the same field

    if( array_key_exists(”lastnamerow-RC”,$_POST)) {
      for($i=2;$i < = (int) $_POST[”lastnamerow-RC”];$i++) {
        if( array_key_exists (”lastname-”.$i,$_POST)) {
          $lastname = $_POST[”lastname-”.$i];
          $emailbody .= “Last Name:” $lastname . “\n”;
        }
      }
    }

  27. fuzzboxer Says:

    Would someone like to convert this to ASP?

  28. JamesD Says:

    Hi Ced

    This looks exactly like what I need for something I have in mind, but although I’m happy working with PHP I’m on shaky ground with javascript.
    I’m developing a game which requires users to enter their instructions each turn via a form; I’m hoping you can either explain, or point me to a good place to read up on, how to do the following with your functions:

    Using the switch behaviour, I want to be able to load a different set of fields from a database table based on which option the user chooses. Is this achievable, and if so, how?

    In the game, the user will have a certain amount of resources to ’spend’ each turn, and each instruction costs a different amount. Is it possible to display a counter which would decrease based on the instructions they choose?

    Thanks!

    James

  29. cedsav Says:

    JamesD.. to answer your first question, wForms doesn’t load parts of the form dynamically. With the Switch behavior you can show/hide sets of fields, but they all need to be loaded with the form.

    For your second question, you would have to develop that functionality. It looks pretty specific to your own application.

  30. tuck Says:

    Any examples in perl to get subsequent values for the same field into an array?

  31. cedsav Says:

    Hi Tuck, sorry I’m not a perl coder.. but if you have anything to share, please send it in. If you need help with the logic, I can help you. Just email me.

  32. tuck Says:

    ced,

    is there a way to keep the “name=somename” even when the row count increments?

    Fantastic work. Thanks a lot.

    Tuck

  33. cedsav Says:

    Tuck, you would need to modify some code in wForms.js.

    From a quick look, I think you’ll need to replace line 327 by line 325
    and remove line 353.
    (make sure you’ve the last version of wForms: v0.99.24)

    I can give you more details if you’re willing to try that.

  34. Edgar Says:

    Hi, its a fantastic function…!
    but I need to know how many times has been repeated the form, there is some like an attribute or statement to know that?
    thanks very much…

  35. Steve Judd Says:

    cedsav,

    I’ve implemented the repeat behavior on a ColdFusion-based site I’m developing, and it works great.

    One thing I had to do, was change the row counter from - to _ because CF doesn’t like variable names with dashes in them.

    I have one issue that I’d like your advice on: I’m using the tinyMCE rich-text editing tool, and it doesn’t work when “repeated”. It uses ids like mce_1, mce_1_parent, mce_1_bold, etc. When repeated, these become mce_1_2, mce_1_parent_2, etc. I think I can get it to work if the I can get the repeat behavior to not duplicate the span (mce_1_parent) that contains the table and IFrame that hold the MCE editor. If I can repeat only the textarea field, then I can have tinyMCE recreate the editing environment.

    Any thoughts on the best way to get the wForms Repeat behavior to not repeat that node?

    Thanks, Steve

  36. cedsav Says:

    Edgar, just read the ‘row count’ paragraph in this post… or maybe I didn’t understand your question ?

    Steve,

    I’m not familiar with tinyMCE, can you post a link to a test page ?
    Maybe you could move the editor out of the repeated section, an use javascript to reposition it at the right place..

  37. Steve Says:

    cedsav,

    I posted an example with further explanation here:

    http://cecf1.unh.edu/sjtest/tinyMCE_repeat.cfm

    Thanks for any ideas you might have. The crux is, I’d like to prevent the repeat behavior from duplicating one particular node and its child nodes (this is the node that the tinyMCE js creates for the WYSIWYG editing iframe.)

  38. cedsav Says:

    Steve, thanks for the test case.

    I created a customization file for you. Get it here:

    tinyMCE / wForms customization file

    Load it after wForms.js It works in Firefox. I haven’t tested it with anything else, so let me know how it goes.

  39. Steve Says:

    Cedric,

    Thanks, the customization works great. I’ve posted an updated example that works with your customization at:

    http://cecf1.unh.edu/sjtest/tinyMCE_repeat_custom.cfm

    View source to see the customization script Cedric provided.

    Happy New Year,
    Steve

  40. Sean Fannan Says:

    Does anyone know if I can implement this using files for the form field types. It seems like implementing this using file fields does not actually upload the file but just sends the tmp image through the string query.

    Any ideas how this can be done. I am trying to set up something where people can upload an unlimited number of files in a form and this would be the perfect solution if only files would work correctly…. :)

    Thanks

  41. cedsav Says:

    Sean, can you post a link to your form ? I’ll check it out