You may be used to adding validation functions for an entire form, but what if you just want to validate an individual form element? Do you really need a form wide validation function for a single field? What if you just want to check that a user submits a number in a field?

It turns out, you don’t actually need to always add form wide validation functions. You can add a validation handler for an individual form element using #element_validate. You can define your own element validation functions. Or, to validate for numbers/integers, use a pre-defined validation handlers with just one line of code.

Example 1: validating for colours

You have a client who only likes the colours blue, yellow, pink and purple. The client does not want a drop down field with only those colours. Instead the client wants the form to be validated so that if a user enters anything other than those colours, they will receive an error.

Standard form wide validation

Let’s have a look at how we would validate a simple form with a form wide validation function.

/**
 * Implements hook_form().
 */
function mymodule_form($form, &$form_state) {
  $form['colour'] = array(
    '#type' => 'textfield',
    '#title' => t('colour'),
    '#size' => 4,
    '#required' => TRUE,
    '#default_value' => variable_get('colour', 'blue'),
  );

  return system_settings_form($form);
}

/**
 * Implements hook_validate().
 */
function mymodule_form_validate($form, &$form_state) {
  $allowed = array('blue', 'yellow', 'pink', 'purple');
  if (!in_array($form_state['values']['colour'], $allowed)) {
    form_set_error('colour', t('You must enter a valid colour.'));
  }
}

We are checking that users submit only blue, yellow, pink or purple in the colour field. If they submit anything else, they will see a form error. The first argument for form_set_error() is the form element to set the error against, which is colour in this case. Therefore, the colour field will be highlighted so the user knows which field has incorrect data.

'colour validate'

Individual form element validation function

To validate a individual element, we need to add an #element_validate to the form element, with the element specific validation function. This function will be passed $form_state and $element. Using the same form example as above, define a validation function for the colour element, rather than for the whole form.

Here is the element validation function:

function mymodule_colour_validate($element, $form_state) {
  $allowed = array('blue', 'yellow', 'pink', 'purple');
  if (!in_array($form_state['values']['colour'], $allowed)) {
    form_error($element, t('You mus enter a valid colour.'));
  }
}

One of the main differences with this and the form wide validation function in the previous example is that you use form_error() rather than form_set_error(). The first argument for form_set_error() is the name of the element to set the error against. With element validation functions, we already have the element, so do not need to pass it as an argument. Therefore, form_error is used instead.

To attach this to the form element, you need to add the following:

  '#element_validate' => array('myform_colour_validate'),

So the form element becomes:

  $form['colour'] = array(    '#type' => 'textfield',
    '#title' => t('colour'),
    '#required' => TRUE,
    '#size' => 4,
    '#default_value' => variable_get('colour', 0),
    '#element_validate' => array('mymodule_colour_validate'),
  );

This might not seem any easier than just using a form validation function. However, when you are validating several form elements, it may be easier and cleaner to split them up, rather than having one large validation function. Clean code is much easier to maintain. You can also reuse the same element validation function across multiple forms. Code reuse is always a good thing!

Example 2: validating for numbers

You need to make sure that users submit only numbers in the number field.

Standard form wide validation

A simple form with a number field and a form wide validation function:

/**
 * Implements hook_form().
 */
function mymodule_form($form, &$form_state) {
  $form['number'] = array(    '#type' => 'textfield',
    '#title' => t('My field'),
    '#required' => TRUE,
    '#size' => 4,
    '#default_value' => variable_get('my_field', 0),
  );
  return system_settings_form($form);
}

/** 
 * Implements hook_validate().
 */
function mymodule_form_validate($form, &$form_state) {
  if (!is_numeric($form_state['values']['number'])) {
    form_set_error('number', t('Field must be Numeric'));
  }
}

We are checking that users enter a number in the number field by passing it through PHP’s is_numeric field. If it is not a number, the user will receive an error and the number field will be highlighted.

'number validate'

Individual form element validation function

Element validation callbacks really come into their own when you are validating for a number because you can use a pre-defined handler. With pre-defined handler, you do not need to add the validation function yourself as it already exists. In the previous example, we checked that the number field was indeed a number by passing it through is_numeric in the form wide validation function.

Drupal has already defined a handler that validates that the data is a number, called element_validate_number.

So we need to add the following to our form element:

  '#element_validate' => array('element_validate_number'),

Therefore, the form element will become:

  $form['number'] = array(    '#type' => 'textfield',
    '#title' => t('My field'),
    '#required' => TRUE,
    '#size' => 4,
    '#default_value' => variable_get('my_field', 0),
    '#element_validate' => array('element_validate_number'),
  );

So it is just one more line of code! No validation function to be seen!

You can also use element_validate_integer() and element_validate_integer_positive() as validation handers

So there we have it. We have looked at 3 ways to validate form data:

  • Form wide validation function
  • Form element validation with custom function
  • Form element validation with pre-defined validation handlers

No doubt you will come across situations where using element validate is a better fit than a form wide validation function. Using element validate where relevant should lead to cleaner code and code reuse. Cleaner code is always a good thing and will make it much easier for you and other developers to maintain.