Our Blog

We always make sure you get the latest updates from devEngineering therefore we have crafted a well organized blog to share what we are planning for you.

Cancellation of required validation in Drupal 6

Hello all. Few weeks ago I was writing yet another module for Drupal and again I’ve encountered trouble with required validation and cancel button. I knew some hacks before, like defining own validation function and redirecting user to some page from this function. But this solution isn’t so good like can appear at first glance. At least because of errors appearing on that page where user was redirected to and to solve this issue we should handle error output…  But in my case this trick didn’t work at all, as I was writing multi-step form and all the data need to be saved, so redirecting user is not a solution.  I googled it here and there, but it didn’t help much. I couldn’t believe that it can’t be done, so I decided to dig into Drupal core and finally I’ve found it. So guys, here is the solution.

Hello all. Few weeks ago I was writing yet another module for Drupal and again I’ve encountered trouble with required validation and cancel button. I knew some hacks before, like defining own validation function and redirecting user to some page from this function. But this solution isn’t so good like can appear at first glance. At least because of errors appearing on that page where user was redirected to and to solve this issue we should handle error output…  But in my case this trick didn’t work at all, as I was writing multi-step form and all the data need to be saved, so redirecting user is not a solution.  I googled it here and there, but it didn’t help much. I couldn’t believe that it can’t be done, so I decided to dig into Drupal core and finally I’ve found it. So guys, here is the solution.

The secret is in function _form_validate() and #needs_validation attribute. You can find this function in form.inc file.

function _form_validate($elements, &$form_state, $form_id = NULL) {
  ...
  if (!isset($elements['#validated']) || !$elements['#validated']) {
      if (isset($elements['#needs_validation'])) {
      // Make sure a value is passed when the field is required.
      // A simple call to empty() will not cut it here as some fields, like
      // checkboxes, can return a valid value of '0'. Instead, check the
      // length if it's a string, and the item count if it's an array.
      if ($elements['#required'] && (!count($elements['#value']) || (is_string($elements['#value']) && strlen(trim($elements['#value'])) == 0))) {
        form_error($elements, $t('!name field is required.', array('!name' => $elements['#title'])));
      }
    }
    ...
  }
  ...
} 

So all what we need to do is unset this attribute for elements with #required flag set to TRUE. And we can do it using#after_build form attribure. So in your form definition or hook_form_alter() function define this attribute like this:

/*
 * Implementation of hook_form_alter().
 */
function module_name_form_alter(&$form, &$form_state, $form_id) {
  $form['cancel_button'] = array(
    '#type' => 'submit', 
    '#value' => t('Cancel'),
    '#submit'   => array('module_name_canel_button_submit'),
  );
  $form['#after_build'][] = 'module_name_form_after_build';
  /*
  * or use this code, if you need to add your handler before others
    if (!isset($form['#after_build'])) {
     $form['#after_build'] = array();
    }
    array_unshift($form['#after_build'], 'namecards_form_after_build');
  */
}

Then define function you want to be executed. In this function we already have values submitted, but form isn’t processed yet. So we can find out which button was pressed, and if it was cancel button, unset the #needs_validation attribute.

/*
 * After build handler
 */
function module_name_form_after_build($form, &$form_state) {
  if($form_state['clicked_button']['#value'] == 'Cancel') {
    _module_name_disable_validation($form);
  }
  return $form;
}

Here is the small function for recursive removing #needs_validation attribute.

/*
 * Recursive function.
 * Removes required validation flag for specified form element and all its children.
 */
function _module_name_disable_validation(&$element) {
  unset($element['#needs_validation']);
  foreach(element_children($element) as $key) {
    _module_name_disable_validation($element[$key]);
  }
}

And finally you can perform your actions in submit function of your cancel button.

/*
 * Submit function for cancel button.
 */
function module_name_canel_button_submit($form, &$form_state) {
  //do something
}

Here is it. Hope it will help someone. :) By the way, if you’re interested how to create multi-step form using Drupal FAPI, let me know in the comments and I’ll try to write a tutorial.
Update: Here is the simple example how to skip validation on user registration form. By clicking cancel button validation is skipped and message posted to the user.