Last weekend I organized and participated in the initiative of Drupal Community Global Sprint Weekend with a location in Costa Rica.
Among talks and contributions, I found an interesting request in Drupal 8, and I want to share with my the implementation.
I want to create a Multi-Step Form because Drupal 8 doesn’t have an official release yet there are several pieces we easily do in Drupal 7, but now we need to learn again how to solve our problems in a different way or Drupal/Symfony Style.
I will create a Multi-Step Form to enable users to find a car providing Year, Body Style and Gas Mileage.
Create a Module
I will skip the explanation about how to create the Module multi_step_form in Drupal 8 because could be generated using the project Drupal Console executing the following command.
$ drupal generate:module
After generating the module, we will use another command to add a Form with properties required as you can see below
$ drupal generate:form:config
As result, we will get a form with a method buildForm like this
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
$config = $this->config('multi_step.multi_step_form_config');
$form['model'] = [
'#type' => 'select',
'#title' => $this->t('Model'),
'#description' => $this->t(''),
'#options' => array('1997', '1998', '1999', '2000', '2001',
'2002', '2003', '2004', '2005', '2006', '2007', '2008',
'2009', '2010', '2011', '2012', '2013', '2014', '2015'),
'#default_value' => $config->get('model'),
];
$form['body_style'] = [
'#type' => 'checkboxes',
'#title' => $this->t('Body Style'),
'#description' => $this->t(''),
'#options' => array('Coupe', 'Sedan', 'Convertible',
'Hatchbac', 'Station wagon', 'SUV', 'Minivan', 'Full-size van',
'Pick-up'),
'#default_value' => $config->get('body_style'),
];
$form['gas_mileage'] = [
'#type' => 'radios',
'#title' => $this->t('Gas Mileage'),
'#description' => $this->t(''),
'#options' => array('20 mpg or less', '21 mpg or more',
'26 mpg or more', '31 mpg or more', '36 mpg or more',
'41 mpg or more'),
'#default_value' => $config->get('gas_mileage'),
];
return parent::buildForm($form, $form_state);
}
Define step property
Inside the Form class, we need a protected property to store the current step of Multi-Step, check the following snippet.
class MultiStepForm extends ConfigFormBase
{
protected $step = 1;
Get parent form
Instead of call parent function buildForm at the end, I will call at the beginning to modify the form before the form is rendered.
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
$form = parent::buildForm($form, $form_state);
Filter form elements by step
Now we need filter what elements of the form will be rendered based on step value, as you can see in the following snippet.
if($this->step == 1) {
$form['model'] = [
'#type' => 'select',
'#title' => $this->t('Model'),
'#description' => $this->t(''),
'#options' => array('1997', '1998', '1999', '2000', '2001',
'2002', '2003', '2004', '2005', '2006', '2007', '2008', '2009',
'2010', '2011', '2012', '2013', '2014', '2015'),
'#default_value' => $config->get('model'),
];
}
Change submit label
Now we need alter the label of submit button to inform the end user that there is the next step or if we reach the end of Multi-Step.
In our case we only have three steps and the code will be like this
if($this->step < 3) {
$button_label = $this->t('Next');
}
else {
$button_label = $this->t('Find a Car');
}
$form['actions']['submit']['#value'] = $button_label;
return $form;
Enable Multi-Step
At the end we need enable the Multi-Step Form behavior, to do this is necessary modify the method submitForm forcing Form Rebuild if we don’t reach the last step of Multi-Step yet using the method setRebuild() part of Form State.
The submitForm method will be similar to the following code
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state)
{
if($this->step < 3) {
$form_state->setRebuild();
$this->step++;
}
else {
parent::submitForm($form, $form_state);
/*$this->config('multi_step.multi_step_form_config')
->set('model', $form_state->getValue('model'))
->set('body_style', $form_state->getValue('body_style'))
->set('gas_mileage', $form_state->getValue('gas_mileage'))
->save();*/
}
}
If you want to test a full implementation of Multi-Step, you can download the module drupal8_multi_step_form.
I hope you found this blog entry useful.