Last updated November 30, 2012. Created by bekasu on February 18, 2010.
Edited by ifernando, changvn, tetherow. Log in to edit this page.
Code sample #10:
This sample creates a "multistep" form with two pages.
<?php
function my_module_menu() {
$items['my_module/form'] = array(
'title' => t('My form'),
'page callback' => 'my_module_form',
'access arguments' => array('access content'),
'description' => t('My form'),
'type' => MENU_CALLBACK,
);
return $items;
}
function my_module_form() {
return drupal_get_form('my_module_my_form');
}
// Adds logic to our form builder to give it two pages. It checks a
// value in $form_state['storage'] to determine if it should display page 2.
function my_module_my_form(&$form_state) {
// Display page 2 if $form_state['storage']['page_two'] is set
if (isset($form_state['storage']['page_two'])) {
return my_module_my_form_page_two();
}
// Page 1 is displayed if $form_state['storage']['page_two'] is not set
$form['name'] = array(
'#type' => 'fieldset',
'#title' => t('Name'),
'#collapsible' => TRUE,
'#collapsed' => FALSE,
);
$form['name']['first'] = array(
'#type' => 'textfield',
'#title' => t('First name'),
'#default_value' => $form_state['values']['first'], // changed
'#description' => "Please enter your first name.",
'#size' => 20,
'#maxlength' => 20,
);
$form['name']['last'] = array(
'#type' => 'textfield',
'#title' => t('Last name'),
'#default_value' => $form_state['values']['last'], // added
);
$form['year_of_birth'] = array(
'#type' => 'textfield',
'#title' => "Year of birth",
'#description' => 'Format is "YYYY"',
'#default_value' => $form_state['values']['year_of_birth'], // added
);
// Add new elements to the form
if (!empty($form_state['storage']['another_name'])) {
$form['name2'] = array(
'#type' => 'fieldset',
'#title' => t('Name #2'),
'#collapsible' => TRUE,
'#collapsed' => FALSE,
);
$form['name2']['first2'] = array(
'#type' => 'textfield',
'#title' => t('First name'),
'#description' => "Please enter your first name.",
'#size' => 20,
'#maxlength' => 20,
'#default_value' => $form_state['values']['first2'],
);
$form['name2']['last2'] = array(
'#type' => 'textfield',
'#title' => t('Last name'),
'#default_value' => $form_state['values']['last2'],
);
$form['year_of_birth2'] = array(
'#type' => 'textfield',
'#title' => "Year of birth",
'#description' => 'Format is "YYYY"',
'#default_value' => $form_state['values']['year_of_birth2'],
);
}
$form['clear'] = array(
'#type' => 'submit',
'#value' => 'Reset form',
'#validate' => array('my_module_my_form_clear'),
);
if (empty($form_state['storage']['another_name'])) {
$form['another_name'] = array(
'#type' => 'submit',
'#value' => 'Add another name',
'#validate' => array('my_module_my_form_another_name'),
);
}
$form['next'] = array(
'#type' => 'submit',
'#value' => 'Next >>',
);
return $form;
}
// New function created to help make the code more manageable
function my_module_my_form_page_two() {
$form['color'] = array(
'#type' => 'textfield',
'#title' => 'Favorite color',
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => 'Submit',
);
return $form;
}
function my_module_my_form_another_name($form, &$form_state) {
$form_state['storage']['another_name'] = TRUE;
$form_state['rebuild'] = TRUE; // Will cause the default submit function
// to be skipped.
}
function my_module_my_form_clear($form, &$form_state) {
unset ($form_state['values']); // ensures fields are blank after reset
// button is clicked
unset ($form_state['storage']); // ensures the reset button removes the
// another_name part
$form_state['rebuild'] = TRUE;
}
// Modifies function so it can validate page 2
function my_module_my_form_validate($form, &$form_state) {
// Validate page 2 here
if (isset($form_state['storage']['page_two'])) {
$color = $form_state['values']['color'];
if (!$color) {
form_set_error('color', 'Please enter a color.');
}
return;
}
$year_of_birth = $form_state['values']['year_of_birth'];
$first_name = $form_state['values']['first'];
$last_name = $form_state['values']['last'];
if (!$first_name) {
form_set_error('first', 'Please enter your first name.');
}
if (!$last_name) {
form_set_error('last', 'Please enter your last name.');
}
if ($year_of_birth && ($year_of_birth < 1900 || $year_of_birth > 2000)) {
form_set_error('year_of_birth', 'Enter a year between 1900 and 2000.');
}
if ($form_state['storage']['another_name']) {
$year_of_birth = $form_state['values']['year_of_birth2'];
$first_name = $form_state['values']['first2'];
$last_name = $form_state['values']['last2'];
if (!$first_name) {
form_set_error('first2', 'Please enter your first name.');
}
if (!$last_name) {
form_set_error('last2', 'Please enter your last name.');
}
if ($year_of_birth && ($year_of_birth < 1900 || $year_of_birth > 2000)) {
form_set_error('year_of_birth2', 'Enter a year between 1900 and 2000.');
}
}
}
// Modifies this function so that it will respond appropriately based on
// which page was submitted. If the first page is being submitted,
// values in the 'storage' array are saved and the form gets
// automatically reloaded.
// If page 2 was submitted, we display a message and redirect the
// user to another page.
function my_module_my_form_submit($form, &$form_state) {
// Handle page 1 submissions
if ($form_state['clicked_button']['#id'] == 'edit-next') {
$form_state['storage']['page_two'] = TRUE; // We set this to determine
// which elements to display
// when the page reloads.
// Values below in the $form_state['storage'] array are saved
// to carry forward to subsequent pages in the form.
$form_state['storage']['page_one_values'] = $form_state['values'];
}
// Handle page 2 submissions
else {
/*
Normally, some code would go here to alter the database with the data
collected from the form. Sets a message with drupal_set_message()
to validate working code.
*/
drupal_set_message('Your form has been submitted');
unset ($form_state['storage']); // This value must be unset for
// redirection! This is because
// $form_state['rebuild'] gets set to TRUE
// when 'storage' is set. See code sample
// #9 for more on this.
$form_state['redirect'] = 'node'; // Redirects the user.
}
}
?>
Comments
Problem with the form fields being reset on page 2
I modified the validate function for the second page, so that an error is thrown in the event that the user enters blue.
The problem is, when the user enters this text, the error message appears, but the field is cleared.
Not only this, when you add more fields, and enter correct values, these are also cleared if an error on another field is thrown.
For a form where the user enters contact details and address, this means if the email field is incorrect, all correct fields will be cleared and the user will have to start entering all fields from scratch.
Any ideas?
How to create a profile when
How to create a profile when the form is submitted
http://drupal.org/node/759588
Where does
Where does $form_state['clicked_button']['#id'] == 'edit-next' get set? Is that a typo for the 'next' button on the first page of the form?
Edit: Ah, I see. Drupal assigns the name 'edit-next' as the default #id of the 'next' button if no #id is defined.
$form_state['clicked_button']['#id'] == 'edit-next'
$form_state['clicked_button']['#id'] == 'edit-next' does not work for me. i tried adding #id in $form['next'] but with no success.
try to add a submit button to
try to add a submit button to the form [next]
this did not work for me in D7 ..
<?php$form_state["rebuild"] = TRUE;
?>
is missing in _submit for page 1
http://stackoverflow.com/questions/2349664/drupal-form-api-and-form-stat...
yes,you are right!
yes,you are right!
drupal ,the sharp skill to eastablish website.
Fatal error: Cannot redeclare class InsertQuery_mysql...
I've used this example for a two-stage form that updates the database. My updates work! Great!
Unfortunately the navigation seems to go haywire if you do not *always* execute the following or similar somewhere in your second submit:
<?php$form_state['redirect'] = '/ateam/join';
$form_state['page_num'] = 2;
$form_state['rebuild'] = TRUE;
?>
Hope this helps someone. It took me days to spot that I had a return in a switch and wasn't always executing the above. The error messages you get are absolutely horrendous and lead nowhere.
Jeb Bushell
$form_state['storage'] not coming over after page 1 to page 2
Everything seems to work fine and I am able to get to the point where on submit I can test for page one or page 2, I set $form_state['storage']['page_two'] = TRUE but when it goes back to the form $form_state['storage'] no longer exists. I don't have it being unset anywhere or set to anything else. Any ideas why the array is disappearing?
[Solved] $form_state['storage'] not coming over after page 1 to
Hi
You have to rebuild the form in submit function.
$form_state["rebuild"] = TRUE;
For more information please have a look on that
http://stackoverflow.com/questions/2349664/drupal-form-api-and-form-stat...