This is a little demo of a small app that allow us to have several forms displayed on the same page, organized by sections, a static multiform can be easily created by putting the form contents on divs and hiding them, then when the user clicks on a specific section we hide the previous div, and show the new one, we can wrap it up everything inside a big form, and submit that.
The approach I did for having this same functionality allows me to:
- Save each section form before editing a new one
- Change any form inputs depending on received data
- Validate in the front and backend each section
The main disadvantage is that for each section I’ll do an ajax call, to submit and retrieve the form.
The first thing I did was to write the main html layout I did a simple 2 column layout to use the left block as a form navigator and the right block to show the actual form.
<div class="left_block_box">
<div class="left_block_title">
Form Steps
</div>
<div id="edit_step_box">
<table width="100%" cellspacing="0" cellpadding="0" border="0" style="font-size: 11px;" id="stepTable">
<tr class="stepSelected">
<td class="formStep">
Name
</td>
<td class="stepEdit">
<span id="formstep1" class="pointer placeEdit">Edit</span>
</td>
</tr>
<tr>
<td class="formStep">
Address
</td>
<td class="stepEdit">
<span id="formstep2" class="pointer placeEdit">Edit</span>
</td>
</tr>
<tr>
<td class="formStep">
Interests:
</td>
<td class="stepEdit">
<span id="formstep3" class="pointer placeEdit">Edit</span>
</td>
</tr>
</table>
</div>
</div>
I’ve used a table so I can navigate more easily the DOM with jquery, but this can be changed an ul and it will work the same, the next thing I wrote was the other column wrapper the right block which will holde the actual form retrieved from the server.
<div class="right_block_box">
<div class="right_block_title" id="formTitle">
Form 1
</div>
<div class="multiform_part">
Aqui va la forma
</div>
<div id="form_step_nav_wrap">
<div id="form_step_nav">
<div id="form_step_left">
<input type="button" value="Previous Step" id="prevStepBtn" />
</div>
<div id="form_step_right">
<input type="button" value="Next Step" id="nextStepBtn" />
<input type="button" value="Preview Data" style="display: none" id="previewBtn" />
</div>
</div>
</div>
</div>
Once I had my basic layout I started with the javascript functionality, the first thing was to create a function that allow me to move from one form to another, passing current form values to the calling script and displaying the new form.
function selectStep(step) {
var thisStep = $(step).children().attr('id');
//get current form data to be passed later
var curr = $(".stepSelected").children(':eq(1)').children().attr('id');
var formData = $("#form_"+curr).serialize();
//add class to selected step
$("#stepTable tr").removeClass('stepSelected');
$(step).parent().addClass('stepSelected');
//put name of step that is going to be edited
$("#formTitle").text($(".stepSelected :eq(0)").text());
$(".multiform_part").html("Loading...");
//send data to php, and draw new form
$.post('processForm.php', {
step: thisStep, saveData: curr, formData: formData
}
,function(data) {
//draw new form
$(".multiform_part").html(data);
}
);
}
This was easy, then I just binded a click event to each step
// handle the edit link on each step
$(".stepEdit").each(function(index){
$(this).click(function(e){
selectStep(this);
}
);
});
And now I have a functional multiform pane, that gets its form from php, the backend was also ver simple to make:
<?php
session_start();
$step = $_REQUEST['step'];
$formData = $_REQUEST['formData'];
function save($step, $data) {
$fields = explode('&',$data);
foreach ($fields as $field) {
$keyVal = explode('=', $field);
$key = urldecode($keyVal[0]);
$val = urldecode($keyVal[1]);
$_SESSION[$step][$key] = $val;
}
}
if ($formData) {
$formStep = $_REQUEST['saveData'];
save($formStep, $_REQUEST['formData']);
}
if ($step) {
switch ($step) {
case 'formstep1':
$html = <<<FORM
<form id="form_{$step}" name="form_{$step}">
<fieldset>
<legend>Personal information</legend>
<div class="fm-req">
<label for="fm-firstname">First name:</label>
<input name="fm-firstname" id="fm-firstname" type="text" value="{$_SESSION[$step]['fm-firstname']}"/>
</div>
<div class="fm-opt">
<label for="fm-middlename">Middle name:</label>
<input id="fm-middlename" name="fm-middlename" type="text" value="{$_SESSION[$step]['fm-middlename']}"/>
</div>
<div class="fm-req">
<label for="fm-lastname">Last name:</label>
<input name="fm-lastname" id="fm-lastname" type="text" value="{$_SESSION[$step]['fm-lastname']}"/>
</div>
</fieldset>
</fieldset>
</form>
FORM;
echo $html;
break;
case 'formstep2':
$html = <<<FORM
<form id="form_{$step}" name="form_{$step}">
<fieldset>
<legend>Address </legend>
<div class="fm-opt">
<label for="fm-addr">Address:</label>
<input id="fm-addr" name="fm-addr" type="text" value="{$_SESSION[$step]['fm-addr']}"/>
</div>
<div class="fm-opt">
<label for="fm-city">City or Town:</label>
<input id="fm-city" name="fm-city" type="text" value="{$_SESSION[$step]['fm-city']}"/>
</div>
<div class="fm-opt">
<label for="fm-state">State:</label>
<input id="fm-state" name="fm-state" type="text" value="{$_SESSION[$step]['fm-state']}"/>
</div>
<div class="fm-req">
<label for="fm-zipcode">Zip code:</label>
<input id="fm-zipcode" name="fm-zipcode" type="text" value="{$_SESSION[$step]['fm-zipcode']}"/>
</div>
</fieldset>
</form>
FORM;
echo $html;
break;
case 'formstep3':
$html = <<<FORM
<form id="form_{$step}" name="form_{$step}">
<fieldset>
<legend>Interests </legend>
<div class="fm-opt">
<label for="fm-int1">Interest 1:</label>
<input id="fm-int1" name="fm-int1" type="text" value="{$_SESSION[$step]['fm-int1']}"/>
</div>
<div class="fm-opt">
<label for="fm-int2">Interest 2:</label>
<input id="fm-int2" name="fm-int2" type="text" value="{$_SESSION[$step]['fm-int2']}"/>
</div>
</fieldset>
</form>
FORM;
echo $html;
break;
case 'getAllData':
echo '<h3>Saved Data</h3>';
echo '<div style="text-align: left;"><pre>';
print_r($_SESSION);
echo '</pre></div>';
break;
}
}
Finally I’ve added some css styles to make it “pretty” and add some other js functionality to navigate back and forth.
You can checkout the working solution here, or get the files here this demo saves user data in session, and the session is destroyed each time you load the index page.