5

I have created my own validate handler:

/**
 * Validate handler.
 */
function my_module_validate($form, &$form_state) {
  $values = $form_state['values'];
  if ($values['type'] == 'line') {
    form_set_error('type', t('MY VALIDATION.'));
  }
}

which is called from a button element:

'preview' => array(
  '#type' => 'button',
  '#value' => t('Preview'),
  '#validate' => array('my_module_validate'),
  '#weight' => 8,
),

which produces this result on submission of an empty form:

enter image description here

The only validation function that I want to run is my own, from my own handler - the last error message - yet all the default validation functions run as well. How do I disable these?

3
  • 1
    Unset '#required' => TRUE, from field. Or make it FALSE.
    – milkovsky
    Commented May 13, 2015 at 8:38
  • 1
    It's working as designed. You don't need to set an error if the value is empty, as the field is required. Your form error will display after the field validate handlers do not return any errors. I've updated my answer - try no value and then a value of '123'. Commented May 15, 2015 at 20:28
  • 1
    As the first comment above suggests, I believe that the presence of '#required' => TRUE, will always trigger the default validation.
    – dbj44
    Commented May 18, 2015 at 8:38

6 Answers 6

6

As per function form_set_error: "If #limit_validation_errors is set on a clicked button, the button must also define a #submit property (may be set to an empty array)." So your preview button should be:

'preview' => array(
  '#type' => 'button',
  '#value' => t('Preview'),
  '#limit_validation_errors' => array(array('map')),
  '#submit' => array(),
),
3

The FAPI allows you to do this without altering the $_SESSION messages array by using #limit_validation_errors.

/**
 * Implements hook_form_alter().
 */
function my_module_form_alter(&$form, &$form_state, $form_id) {
  if ($form_id == 'my_form_id') {
    $form['my_textfield'] = array(
      '#type' => 'textfield',
      '#title' => t('Some title'),
      '#required' => TRUE,
      '#element_validate' => array('my_element_validate'),
    );
    $form['preview'] = array(
      '#type' => 'button',
      '#value' => t('Preview'),
      '#limit_validation_errors' => array(array('my_textfield')),
    );
  }
}

/**
 * My textfield element validate handler.
 */
function my_element_validate($element, &$form_state, $form) {
  // Check the value here.
  if ($element['#value'] == '123') {
    form_error($element, t('123 not allowed!'));
  }
}
3
  • Thanks, but the default validation still appears to run using this method.
    – dbj44
    Commented May 11, 2015 at 12:56
  • @24ma13wg If you are doing it right, you shoouldn't see the errors for #required => true. #limit_validation_errors is how we usually bypass the other validation errors.
    – AKS
    Commented May 11, 2015 at 15:50
  • Thanks @Ayeshk. My understanding is that that #limit_validation_errors just tells Drupal to limit validation to the specified form elements, but does not have anything to do with which validate functions run. I've added the code I tried to my answer.
    – dbj44
    Commented May 12, 2015 at 7:02
1

I have found a way that works:

$form_required_marker = array('#theme' => 'form_required_marker');
$required = ' ' . drupal_render($form_required_marker);

'map' => array(
  '#type' => 'select',
  '#title' => t('Map') . $required,
  // '#required' => TRUE,
  '#options' => array(
    '' => t('- Select -'),
    'map1' => t('Map 1'),
    'map2' => t('Map 2'),
  ),
),

...then specify a custom validation handler with #validate.

1

You see different validation error, because your validation callback is called after the error happened. One solution is to call form_clear_error() to clear previous errors and set the new one. Or unset specific element validation error in your element validate callback, e.g.

/**
 * Implements callback for #element_validate Form API.
 */
function my_module_map_validate($element, &$form_state, $form) {
  if (empty($element['#value'])) {
    // Clear previous validation error for this element.
    $errors = &drupal_static('form_set_error', array());
    $err_key = $element['#field_name'] . '][' . LANGUAGE_NONE;
    if (array_key_exists($err_key, $errors)) {
      unset($errors[$err_key]);
    }
    form_error($element, t('xyz'));
    return;
  }
}
0

I've part solved the problem by using this custom function - but it's not perfect.

It works perfectly on first valiadtion failure, but if I create another validation failure, I get a blank error message and then this error:

Notice: Undefined offset: 0 in theme_status_messages().

Code:

/**
 * Validate handler.
 */
function my_module_validate($form, &$form_state) {
  if ($type = $form_state['values']['type']) {
    switch ($type) {
      case 'map':
        $names = array(
          'line_sub_type',
          'margin_top',
          'margin_right',
          'margin_bottom',
          'margin_left',
          'x_axis_label',
          'y_axis_label',
          'date_time_format',
        );
        break;
      case 'line':
        $names = array(
          'map',
          'land_color',
          'boundary_width',
          'color_key',
          'lighter_end',
          'darker_end',
          'units_format',
        );
        break;
      }  
    foreach ($names as $name) {
      my_module_form_unset_error($name);
    }
  }
}

/**
 * Clear a form element error.
 */
function my_module_form_unset_error($name) {
  $errors = &drupal_static('form_set_error', array());
  $removed_messages = array();
  if (isset($errors[$name])) {
    $removed_messages[] = $errors[$name];
    unset($errors[$name]);
  }
  $_SESSION['messages']['error'] = array_diff($_SESSION['messages']['error'], $removed_messages);
  if (empty($_SESSION['messages']['error'])) {
    unset ($_SESSION['messages']['error']);
  }
}
0

In hook_form_alter() function, you can unset the default validation rules and then specify your validation function as validate handler

function mymodule_form_alter(&$form, &$form_state, $form_id) {
  if ($form_id == 'YOUR FORM ID') {
    unset($form['#validate']);
    $form['#validate'] = array('my_module_validate');
  }
}

Please note that this change will completely remove the form validations from all the fields and you need to handle the validation of all the fields individually.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.