Yet another method to simplify making multipage/multistep Drupal forms

Blog
Drupal

In Drupal there are many different methods to turn long forms into multipage/multistep forms. The most known one is perhaps the great ctools module or even custom solutions using Drupal’s form API. However as you may agree with me none of these solutions are really that easy, specially when it comes to Ajax. Therefore many developers in Drupal community tried or still trying to find an even easier method. What I’m going to introduce to you is yet another magical method :).

Hopefully for content types (entity bundles) in Drupal we have Field Group module which can do lots of things including turning simple forms into multipage forms without a single line of code! However Field Group does not support Ajax and relies entirely on JavaScript.  It causes some very important limitation for advanced and complex forms. These forms usually have complex validations, fields on each page may require calculations based on fields from previous pages, or on some special cases it might be needed to have regular JavaScript less and Ajax less multipage form.

That would have been great if we could use the Field Group for all purposes, wouldn’t it? It was my idea for writing Field Group Ajaxified Multipage. Although the name of the module contains Ajax and Field Group, it works without Field Group module for custom forms and Ajax is also optional. I hope it makes life for you fellow developers easier J. Now let’s see how it works.

The first feature which enhances Field Group multipage feature just like Field Group module itself is extremely easy to use.

  • Setup your multipage field groups as usual for your entity/node
  • In your entity/node fields list , edit your multipage field group properties and check Ajaxify option
  • You can also enable only "Non JavaScript Multistep" option which does not require JavaScript to work. It's very useful for debugging purposes or very complex multistep forms. remember that the ajaxify should be disabled for this to work
  • Skip button : You can add skip button for any of the steps you like, simply clone the next button added by this module and change its title to t('Skip this step')

That’s it, but if you’re a developer you can do much more. The module adds several parameters to $form_state variable, you can use these parameters to decide what happens on the form considering the form step.

  • $form_state['field_group_ajaxified_multipage_enabled']
  • $form_state['field_group_ajaxified_multipage_group']

Here is a sample code :

<?php
function hook_form_alter(&$form, &$form_state, $form_id) {
  if (isset($form_state['field_group_ajaxified_multipage_enabled']))
  if ($form_state['field_group_ajaxified_multipage_enabled']) {
    $step = empty($form_state['storage']['field_group_ajaxified_multipage_step']) ? 1 : $form_state['storage']['field_group_ajaxified_multipage_step'];
    $page_group = $form_state['field_group_ajaxified_multipage_group'];

    //Best practive for accessing variables, it works even when this ajax grouping is disabled
    if (isset($form_state['values'])) {
      $values = $form_state['values'];
      if (isset($form_state['field_group_ajaxified_multipage_enabled']) && isset($form_state['storage']['all']['values'])) {
        $values = $form_state['storage']['all']['values'];
      }
    }

    if ($page_group['children'][$step-1] == 'group_two') {
      $form['actions']['skip'] = $form['actions']['next'];
      $form['actions']['skip']['#value'] = t('Skip this step');
      $form['actions']['skip']['#limit_validation_errors'] = array();
    }

    if ($step == count($page_group['children'])) {
      unset($form['actions']['preview']);
    }
  }
}
?>

In some cases you may want to alter the form after this module, for those cases there is new hook introduced by this module to use, it's similar to hook_form_alter :

  • hook_field_group_ajaxified_multipage_form_alter();
  • hook_field_group_ajaxified_multipage_form_BASE_FORM_ID_alter();
  • hook_field_group_ajaxified_multipage_form_FORM_ID_alter();
/**
 * Implementation of hook field_group_ajaxified_multipage_form
 */
function mymodule_field_group_ajaxified_multipage_form_alter(&$form, &$form_state, $form_id) {
}

So what about custom forms? The only difference is that instead of using Field UI to define form pages, an special paramter in $form can be used for form array. Just like this :

<?php
function myform() {
    $form['#groups_custom'] = array (
      'group_measurements' => array(
        'group_name' => 'group_measurements',
        'label' => 'Measurements',
        'format_type' => 'multipage',
        'children' => array (
          'gender',
          'birthday',
        ),
      ),
      'group_goal' => array(
        'group_name' => 'group_goal',
        'label' => 'Goal',
        'format_type' => 'multipage',
        'children' => array (
          'overall_objectiv',
          'duration',
        ),
      ),
      'group_steps' => array(
        'group_name' => 'group_steps',
        'label' => 'Steps',
        'format_type' => 'multipage-group',
        'children' => array (
          'group_measurements',
          'group_goal',
        ),
        'format_settings' => array (
          'label' => 'Steps',
          'instance_settings' => array (
            'ajaxify' => '1',
            'nonjs_multistep' => '0',
            'classes' => ' group-steps field-group-multipage-group',
            'page_header' => '3',
            'page_counter' => '1',
            'move_button' => '1',
            'move_additional' => '1',
          ),
        ),
      ),
    );
}
?> 

And the last thing is, unfortunately due to a bug in Drupal core, this method does not work well for registration form (admin/people/create), however a patch is proposed that fixes the problem. If you're interested please join the issue and help in making it ready (RTBC)

#208790: Changing "Create new account" button text breaks admin/user/user/create form

Your rating: None Average: 4.8 (4 votes)

Comments

rooby's picture

Another related module is the

Another related module is the page break field module.

I have not tried it yet but it might be of interest to you.

Pabitra Dash's picture

I am using your module for a

I am using your module for a multipage form. But I am having some issues. For some reason the required fields validation does not work on a page when I go the next page. It lets me go to the next page even if the previous page had some empty fields which are set as required fields. However, if I come to the page where I was expecting to see validation errors, and then try to go to the next page then I see the validation errors. When the validation errors are being displayed and required fields are still empty, if I select next step it lets me go to the next page.

Any idea what might be going wrong here?

Thanks.
PK

admin's picture

Yes sometime it happens and

Yes sometime it happens and is reported by other users as well Required fields are not required
Don't know yet what's causing it but you might want to join that issue and provide as much as info as you can. It helps me prepare as fix

Pabitra Dash's picture

Any idea why this hook is not

Any idea why this hook is not getting invoked.

hook_field_group_ajaxified_multipage_form_alter()

I have implemented the above hook in my custom module but it is not being invoked. If I change it to normal hook_form_alter() that gets invoked.

Thanks,
PK

admin's picture

It will only gets invoked for

It will only gets invoked for forms that are altered by the module.

Pabitra Dash's picture

I am very new to Drupal. This

I am very new to Drupal. This may sound like a silly question. When you say 'altered by the module" which module are you referring to. Is it your module that adds the multipage form functionality or my custom module that tries to alter the multipage form?

PK

Pabitra Dash's picture

I am very new to Drupal. This

I am very new to Drupal. This may sound like a silly question. When you say 'altered by the module" which module are you referring to. Is it your module that adds the multipage form functionality or my custom module that tries to alter the multipage form?

PK

Marcos's picture

Hi, thank you for this

Hi, thank you for this module! There is an issue I can't solve when using your module. I need my custom module to perform some checks and disable the next, prev buttons programatically based on values filled in the form. But I can't find $form['actions']['next'] (as per your code) in the $form array. I did a debug($form) and tried to find any elements that could control the next and prev buttons, but found nothing. Is there something I could be missing here? Thank you!