How to suppress validation errors with a back button on a Drupal multistep form

Multistep forms are a great improvement to the user experience, especially if a form has a lot of fields. Rather than users having to deal with an overly long form, you can present them with a series of steps with just a few fields on each. Most multistep forms feature a back button. The problem is, when you have required fields on a particular step, and the field is not filled in, the user will get a validation error when hitting back. This is because the Drupal form is being validated and all of the necessary validation handlers are being called and validation rules processed. Receiving a validation error when simply trying to go back on a step is not a great user experience!

But fear not. You can still have your nice multistep form and get rid of these pesky errors when hitting a back button. The problem is solved by adding the #limit_validation_errors property to the back button.


Update 11th October - The fix using #limit_validation_errors described in this post has been rolled into the Multistep Nodeform module. See the bottom of this post for more details.


In order to demonstrate, let's set up a multistep form.

Set up the multistep form

I am using the Multistep Nodeform module to create the multistep form. After you enable the Multistep Nodeform module, you will see a new field appear on the manage field screen for any content type. The new field is titled "Add new step". All you need to do is add the steps with a label for each and then drag your fields under each step.

I have configured the Article content type to be multistep. I have added two steps, Step 1 and Step 2 and dragged Title and Tags under Step 1 and Body and Image under Step 2. See below for the manage field form for the Article content type (found here: admin/structure/types/manage/article/fields):

Configuring Node Multistep steps

When you add Article content, the node form will now be multi step.

Step 1

Step 2

Validation error on back button

If you hit the back button without filling the required body field, you will get a validation error and be prevented from going back. This is clearly a bad user experience as any user would expect to be able to go back from a step without completing it.

Validation error after hitting back with required body field

Solution

The solution is to limit validation on the back button and only the back button. We do not want to see validation errors if no, or invalid, data is added to a step when the user is simply going back. Fortunately, Drupal provides a Form API property for exactly this case, the #limit_validation_errors property.

In order to add the #limit_validation_errors property to the Article node form, you need to implement hook_form_alter() and add to the element for the back button. The machine name for the back button in the Multistep Nodeform module is called previous.

I have created a module called Article and my implementation of hook_form_alter is a function called article_form_alter(). You can add your hook implementation to another custom module if you prefer.

In the code snippet below, #limit_validation_errors is added to the previous element. It is assigned an empty array, which means no validation will be applied.

  1. /**
  2.  * Implements hook_form_alter.
  3.  */
  4. function article_form_alter(&$form, &$form_state, $form_id) {
  5. if ($form_id == 'article_node_form') {
  6. $form['actions']['previous']['#limit_validation_errors'] = array();
  7. }
  8. }

This is actually not enough and a lot of people seem to be going wrong here. You must also add the #submit property to the button, like so:

  1. /**
  2.  * Implements hook_form_alter.
  3.  */
  4. function article_form_alter(&$form, &$form_state, $form_id) {
  5. if ($form_id == 'article_node_form') {
  6. $form['actions']['previous']['#submit'][] = array();
  7. $form['actions']['previous']['#limit_validation_errors'] = array();
  8. }
  9. }

The (API documentation)[https://api.drupal.org/api/drupal/includes%21form.inc/function/form_set_error/7] makes this clear: #limit_validation_errors does not have any effect if #submit is not set.

We don't actually need a submit handler function, so simply set an empty array.

Partial validation

You may have a need to have a mix of limited and full validation on the same step. In the example of the Article multistep form, let's say that you want to allow users to go back without entering any data in the body field, but you want to ensure they upload an image. In this case, you can add the element where the validation rules still apply to the #limit_validation_errors array. In the code snippet below, I have added field_image.

  1. function article_form_alter(&$form, &$form_state, $form_id) {
  2. if ($form_id == 'article_node_form') {
  3. $form['actions']['previous']['#submit'][] = array();
  4. $form['actions']['previous']['#limit_validation_errors'] = array(array('field_image'));
  5. }
  6. }

The image field needs to be made a required field for this to have any effect. Now if I hit the back button without uploading an image, I will get a validation error.

Validation error after hitting back with required image field

Use with caution

You should only use the #limit_validation_errors property on buttons that do not result in data being saved to the database when triggered. Do not use it on a button that results in data being saved, such as the save button, because then the data will be saved without any validation.

Wrapping up

The #limit_validation_errors is one of those little gems in the Form API that make your life as a developer a lot easier. It allows for a pragmatic approach where you might not always want to validate when a specific button is triggered. Use it with care!

Update - 11th October

The fix using #limit_validation_errors described in this post has been rolled into the Multistep Nodeform module. So you don't need to do this yourself in a form alter if you are using the Multistep Nodeform module. You may still find the problem in other multi-step modules. As mentioned in the comments below, it is recommended to raise this sort of thing as an issue in the issue queue of the module itself and contribute a patch. You may still find yourself needing to use the form alter approach technique outlined in this post (as well as contributing a patch in the issue queue) if you are under a hard deadline and don't have time to wait for the patch to be committed and don't want to have to deal with the ramifications of having a contributed module that you need to patch each time you upgrade (that problem disappears once the patch has been committed).

Comments

That's actually an issue from multistep node form module. We usually alter the flow of a module to add some feature we need or change its behavior, but when it's actually an issue we should just go away and fix it upstream. I have posted a patch that fixes it in https://drupal.org/node/2105507 and it would be awesome if you helped test it and get it to RTBC status.

Blair Wadman's picture

Thanks for your comments. I have updated the post to reflect that has now been fixed and regarding fixing upstream via patching.

Hi.
I've committed a patch to Multistep Nodeform that fixes the back button as you suggested.

Thanks for the hint!

Blair Wadman's picture

Hi Stefan, thanks for committing the patch, much appreciated.

I have used multstep form dev module.after completing go to next step and from where i want to come on step1 then it always shows validation error.Although i have used form alter but it does not work.

Hi, I have the same problem of the user before me. I've added the code in a form alter hook and also I tried via patch but when I click Back the form gets validated.
The funny thing is that if I apply the code to the actual submit button it works perfectly and the validation gets skipped. What I see is that if we don't manually add the lines
$form['actions']['previous']['#submit'][] = array();
$form['actions']['previous']['#limit_validation_errors'] = array();

the action "previous" is not even in the list of actions. So I don't really know what the button "previous"is using to go back. Please help.

I have a problem using #limit_validation_errors for a submit button on which I dont want all the validations to run. Here's my custom submit button :

$form['actions']['draft'] = array(
'#type' => 'submit',
'#value' => 'Save as draft',
'#submit' => array(''),
'#limit_validation_errors' => array(
array('title'), // Validate $form_state['values']['title'].
),
);
It works perfectly in the sense that it checks the validation on the title field only, but the weird thing is, it does not submit any other field's values when submitted. I wrote a custom submit handler to check that. However, the values are present in $form_state['input'] but not in $form_state['values'].

What I want simply is, this form will submit with just the values given and overlook the validations when this custom submit button is clicked.

FYI : I can get $form_state['values'] perfectly in my custom validate function.

Any ideas? What am I doing wrong here?

Add new comment