How to validate a single Drupal form element

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.

  1. /**
  2.  * Implements hook_form().
  3.  */
  4. function mymodule_form($form, &$form_state) {
  5. $form['colour'] = array(
  6. '#type' => 'textfield',
  7. '#title' => t('colour'),
  8. '#size' => 4,
  9. '#required' => TRUE,
  10. '#default_value' => variable_get('colour', 'blue'),
  11. );
  12.  
  13. return system_settings_form($form);
  14. }
  15.  
  16. /**
  17.  * Implements hook_validate().
  18.  */
  19. function mymodule_form_validate($form, &$form_state) {
  20. $allowed = array('blue', 'yellow', 'pink', 'purple');
  21. if (!in_array($form_state['values']['colour'], $allowed)) {
  22. form_set_error('colour', t('You must enter a valid colour.'));
  23. }
  24. }

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.

Validation error on colour field

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:

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

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:

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

So the form element becomes:

  1. $form['colour'] = array( '#type' => 'textfield',
  2. '#title' => t('colour'),
  3. '#required' => TRUE,
  4. '#size' => 4,
  5. '#default_value' => variable_get('colour', 0),
  6. '#element_validate' => array('mymodule_colour_validate'),
  7. );

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:

  1. /**
  2.  * Implements hook_form().
  3.  */
  4. function mymodule_form($form, &$form_state) {
  5. $form['number'] = array( '#type' => 'textfield',
  6. '#title' => t('My field'),
  7. '#required' => TRUE,
  8. '#size' => 4,
  9. '#default_value' => variable_get('my_field', 0),
  10. );
  11. return system_settings_form($form);
  12. }
  13.  
  14. /**
  15.  * Implements hook_validate().
  16.  */
  17. function mymodule_form_validate($form, &$form_state) {
  18. if (!is_numeric($form_state['values']['number'])) {
  19. form_set_error('number', t('Field must be Numeric'));
  20. }
  21. }

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.

Validate error on number field

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:

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

Therefore, the form element will become:

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

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.

Comments

Nice tutorials on form validation, thanks

This helped me too! Thanks a lot!

David

Thanks for the post. Have you tried using this approach with ajaxified form elements? Exactly your examples, but with #ajax => array('callback'=>...). It seems to work only theoretically - struggling big time with having the errors set. In my case, the errors are set only when the ajax callback is triggered by a submit or button element. Any idea or hints?

this was very helpful thanks

how to validate email id i want to check email id is already register or not

Blair Wadman's picture

In the validation function, you could call user_load_by_mail($mail), passing in the email address from the field. If it does not exist, it will return false. If it does exist, it will return the user object. So assuming you want to throw a validation error if the email address does exist, you would do so if a user object is returned from user_load_by_mail($mail).

As an alternative, you could try checking the email address with user_validate_mail($mail).

Thanks for the great tutorial.

One note: Individual form element validation function takes &$form_state as an argument, so it's passed as a reference. Quite important if you want to tweak/change the value. See: #element_validate @ api_drupal_org

Thank you very much it clarified a lot my interrogations

Very useful, thanks!

Add new comment