Dynamic Fields in Multiple Pages for FormIt

Sometimes dealing with FormIt, a MODX primary extra to handle HTML form, makes confusion, especially when the form has unusual kind of fields, or a complex form of fields.

This post is about to reveal how we can use HTML dynamic fields, in multiple pages, and then send the report via email, by processing the submission using FormIt. I will use bootstrap's styling as it's popular and fortunately this site is using it.

The Idea

For this example, we will use simple fields for each pages. The basic idea of the page flow is like this.

Step 1

Basic information

step 1

Step 2

Additional information

step 2

Step 3

Send e-mail.

Step 4

Thank you page.

The Challenges

  1. When FormIt's validator returns fail and goes back to the same page, the dynamic fields that are being added should be shown back.
  2. The values from the previous page must be brought through to the next page.
  3. All values from all pages must be brought through to the email chunk
  4. The dynamic fields must be arranged back inside the email chunk.

The Codes

Let's begin to create the template/page, snippets and chunks one by one from scratch, starting from the basic HTML code for the form.

Example

Personal Details

HTML code

Read the comments between the lines.

<form action="" method="post" class="form-horizontal" role="form">
    <fieldset>
        <legend>Personal Details</legend>
        <div class="form-group">
            <label for="name" class="col-sm-2 control-label">Name</label>
            <div class="col-sm-4">
                <!-- this is a common field -->
                <input
                    name="name"
                    type="text"
                    value="" 
                    placeholder="Name (required)"
                    required="required"
                    class="form-control required"
                    >
                <div class="validate"></div>
            </div>
        </div>
        <!-- This is the dynamic field we want to manipulate -->
        <div class="form-group">
            <label for="telephone" class="col-sm-2 control-label">Telephone</label>
            <div class="col-sm-4">
                <button 
                    type="button"
                    class="btn btn-warning btn-sm" 
                    onclick="addRow(this);"
                    >
                    <span class="glyphicon glyphicon-plus"></span> Click to add more
                </button>
                <div class="validate"></div>
            </div>
        </div>
        &nbsp;
        <div class="row">
            <div class="col-sm-4 col-sm-offset-2">
                <input
                    type="submit"
                    name="go"
                    class="btn btn-success btn-sm"
                    value="Submit"
                    >
            </div>
        </div>
    </fieldset>
</form>
<!-- This is the javascript to add and remove the field dynamically. -->
<!-- The value itself is taken from the field we want to duplicate. -->
<!-- Notice that the name of the dynamic field has square brackets ([]) because it will hold multiple values. -->
<script>
    function addRow(button) {
        var newRow = '<div class="input-group"><input name="telephone[]" type="text" value="" placeholder="+1 800 123456" required="required" class="form-control required" ><span class="input-group-btn"><button class="btn btn-default" type="button" onclick="removeRow(this);" ><span class="glyphicon glyphicon-minus"><\/span><\/button><\/span><\/div>' + "&nbsp;\n";
        $(newRow).insertBefore($(button));
    }
    function removeRow(button) {
        $(button).parent().parent().remove();
    }
</script>

That said, the dynamic field of var newRow can be seen like this.

<div class="input-group">
<input
name="telephone[]"
type="text"
value=""
placeholder="+1 800 123456"
required="required"
class="form-control required"
>
<span class="input-group-btn">
<button
class="btn btn-default"
type="button"
onclick="removeRow(this);"
>
<span class="glyphicon glyphicon-minus"></span>
</button>
</span>
</div>

Now, let's break it to pieces.

Snippets

FormIt

FormIt properties:

  • &hooks=`redirect` and &redirectTo=`9` are used to redirect the page to the next form page.
  • &store=`1` and &submitVar=`go` are used to store the values of the current page to the next form page.
  • &validate=`name:required,telephone:required` is used to make sure the fields are filled up.

fiDynamicFields

fiDynamicFields is the snippet to manipulate this dynamic form, to parse the HTML code and to hold the submitted values if the page goes back to the same page.

It only needs 3 parameters:

  • &itemTpl - the dynamic row field
  • &wrapperTpl - to wrap the item's output
  • &phsPrefix - to give prefix to placeholders, in this case the default is: dynfield.

chunkToJsProperty

chunkToJsProperty is a helper snippet to modify chunk's HTML to make it validated as javascript's value.

Chunks

step1DynamicFields.item

step1DynamicFields.wrapper

If you have multiple dynamic fields in one page, make sure you have the Javascript's function name different, and change the related functions' names on chunk as well.

The Codes - Page 2

Example

Experiences

HTML Code

This is the example of the initial form in next step.

<form action="" method="post" class="form-horizontal" role="form">
    <fieldset>
        <legend>Experiences</legend>
        <div class="form-group">
            <label for="inputEmail3" class="col-sm-2 control-label">Positions</label>
            <div class="col-sm-4">
                <button 
                    type="button"
                    class="btn btn-warning btn-sm" 
                    onclick="addRow(this);"
                    >
                    <span class="glyphicon glyphicon-plus"></span> Click to add more
                </button>
                <div class="validate"></div>
            </div>
        </div>
        &nbsp;
        <div class="row">
            <div class="col-sm-4 col-sm-offset-2">
                <input
                    type="submit"
                    name="go"
                    class="btn btn-success btn-sm"
                    value="Submit"
                    >
            </div>
        </div>
        <!-- step 1 submission is being held in here -->
        <input type="hidden" name="name" value="">
        <input type="hidden" name="telephone" value="">
    </fieldset>
</form>

<script>
    function addRow(button) {
        var newRow = '<div class="input-group"><input name="position[]" type="text" value="" placeholder="Past position" required="required" class="form-control required" ><span class="input-group-btn"><button class="btn btn-default" type="button" onclick="removeRow(this);" ><span class="glyphicon glyphicon-minus"><\/span><\/button><\/span><\/div>' + "&nbsp;\n";
        $(newRow).insertBefore($(button));
    }
    function removeRow(button) {
        $(button).parent().parent().remove();
    }
</script>

In this part,var newRow can be seen like this:

<div class="input-group">
    <input 
        name="position[]"
        type="text"
        value=""
        placeholder="Past position"
        required="required"
        class="form-control required"
        >
    <span class="input-group-btn">
        <button
            class="btn btn-default"
            type="button"
            onclick="removeRow(this);"
            >
            <span class="glyphicon glyphicon-minus"></span>
        </button>
    </span>
</div>

So, we will break this form to pieces like following:

Snippets

FormIt

FormIt properties:

  • &hooks=`redirect`and&redirectTo=`10`are used to redirect the page to thank you page.
  • &store=`1`and&submitVar=`go`are used to store the values of the current page to email chunk.
  • &validate=`position:required`is used to make sure this field is filled up.
  • &hooks=`email`, &emailTpl=`emailTpl`, &emailSubject=`Submission - [ [+name]]`, &emailTo=`me@example.com` are for email process.

FormItRetriever

FormItRetriever is an assistance snippet for FormIt that will grab the data of a user's last form submission via FormIt.

At this point, you will realize that the values from previous form will be stored as single value and delimited with comma(s).

Chunks

step2DynamicFields.item

step2DynamicFields.wrapper

Be notice about which chunk var newRow is taking.

Email

When the last form is submitted, FormIt will start to run&hooks in their order one by one.

In emailTpl chunk, you will need to revert the dynamic values again so they will be shown in multiple rows.

For this purpose, we will need another helper snippet to process them.

Use the snippet several times in email template if you want to grab the data separately.

HTML Code

Snippet

fiDynamicFieldsEmail

The required properties are:

  • &fields - to let snippet knows which fields to be process. You need to set the fields separated with comma.
  • &itemTpl- the dynamic row field
  • &wrapperTpl- to wrap the item's output
  • &phsPrefix- to give prefix to placeholders, in this case the default is:dynfield.

Chunks

These chunks are the templates to render the fields back as multiple rows into email template. Create several sets of chunks for different rows of data.

step1DynamicFieldsEmail.item

step1DynamicFieldsEmail.wrapper

step2DynamicFieldsEmail.item

step2DynamicFieldsEmail.wrapper

Summary

It looks so hard, doesn't it?

Well, just remember the rule of thumb:

  1. Snippets are only to parse the returning/given values, both on failed return and email template
  2. Dynamic fields have square brackets ( [ ] ) on their names
  3. Chunks in forms are used to form back the fields into the expected rows.
  4. Chunks in email are used to separate the output to several part of the message in email body.

Enjoy the dynamic fields with FormIt from now on.



Comments

blog comments powered by Disqus