depage-forms: validation of html5 forms (Part II)

article by Frank Hellenkamp

Validation of HTML form data

Thanks to the new HTML Standard and the WHATWG Group it is easier than before to have Browsers show standard errors when a user does not provide valid data inside an input element. Unfortunately this only works in newer Browsers, and not in older ones (e.g. Internet Explorer 8). 

 

To make it easier for developers, depage-forms provides an way easy way to add validation to forms that works in all three different places at the same time: 

  • on the server

  • in the browser, based on the new html standard

  • in the browser, based on javascript

This is a part of the ongoing series about depage-forms

Standard Input Elements

There are various standard input elements that are part of the HTML standard and will be validated by the browser. E.g. input[type=email] and input[type=url]. Other input elements are presented with a different user interface or as native controls like input[type=number], input[type=range] or input[type=date]

 

depage-forms uses these inputs but extends and enhances the behaviour in various places. 

Required Fields

The most simple case for validation happens when an input is required

/*
 * The most simple validation: 
 * Setting 'required' so that a user has to input *something*
 */
$form->addText('username', array(
    'label' => 'User name', 
    'required' => true,
));
$form->addBoolean('accept', array(
    'label' => 'Accept terms and conditions.', 
    'required' => true,
));

Validation based on type

depage-forms also validates based in the input-type. And you can provide an optional error-message that will be displayed, in case the user does not provide valid data. 

/*
 * Validation based on type:
 * The user has to provide a valid email/url for these
 * fields. If the reuqired flag is not set, the user
 * can leave the field empty, but when he fills in 
 * something, it has to be a valid email/url.
 */
$form->addEmail('email', array(
    'label' => 'Email address',
    'required' => true,
    'errorMessage' => "Please enter a valid Email",
));
$form->addUrl('website', array(
    'label' => 'Website',
    'required' => true,
    'errorMessage' => "Please enter a valid Website address",
));

Validating number with min/max values

For numbers there is the special case of minimum and maximum numbers: 

/*
 * Number input element:
 * By default, min, max, step values aren't set 
 * (Depend on browser, step is usually 1). 
 * Returns float value.
 */
$form->addNumber('Number', array(
    'min'   => 0,
    'max'   => 10,
    'step'  => 2,
));

/*
 * Range input element:
 * Same as number input element but with a slider interface.
 */
$form->addRange('Range', array(
    'min'   => 0,
    'max'   => 10,
));

Validation based on regular expressions

The next way to validate values are regular expressions. These inputs will be validated on the server and also in newer browsers that understand the pattern-attribute. 

/*
 * The validator pattern has to match the complete string (HTML5 spec). Here
 * are some examples:
 */
$form->addText('singleLetter', array(
    'label' => 'Single letter', 
    'required' => true, 
    'validator' => '/[a-zA-Z]/',
));
$form->addText('lettersAndNumbers', array(
    'label' =>'One ore more letters or numbers', 
    'required' => true,
    'validator' => '/[a-zA-Z0-9]+/',
));

Validation with closures

Instead of validation with a regular expression, you may also provide a closure function to validate the input value. The closure function will only be validated on the server, not on the client. 

/*
 * adds a closure validator:
 * attach a function to the input.
 * In this case you must enter "2" oder a string
 * containing "yes" to pass validation.
 */
$form->addText('closure', array(
    'label' => 'closure validated', 
    'required' => true,
    'validator' => function($value) {
        if ($value == 2) {
            return true;
        } else {
            return strpos($value, "yes") !== false;
        }
    },
));

Difference to the HTML standard

There is one important case where depage-forms behaves differently from simple html-inputs: Checkboxes. 

 

In HTML5 if a checkbox is required, every required checkbox in a set has to be checked to validate. In depage-form the boolean field works the same way. If it is required, you have to check it. 

 

But if you use the input-multiple with the checkbox skin, the user only has to check one checkbox of a set to pass validation (analogous to the radio-buttons/input-single). 

Javascript Validation

For Browsers that don't support the direct validation of input fields or to display the error-messages directly, we can activate the validation with javascript. We have to include jQuery, the jquery-tools and the effects.js into the html-code. 

 

Here a full example: 

<?php
/*
 * Load the library...
 */
require_once('../../htmlform.php');

/*
 * Create the example form 'jsExample'
 */
$form = new depage\htmlform\htmlform('jsExample');

/*
 * Add the various input elements to the form by calling the '"add" + element
 * type' method.
 */
$form->addText('username', array('label' => 'User name', 'required' => true));
$form->addEmail('email', array('label' => 'Email address'));
$form->addBoolean('accept', array('label' => 'Accept terms and conditions.', 'required' => true));

/*
 * The validator pattern has to match the complete string (HTML5 spec). Here
 * are some examples:
 */
$form->addText('singleLetter', array('label' => 'Single letter', 'required' => true, 'validator' => '/[a-zA-Z]/'));
$form->addText('letters', array('label' =>'One ore more letters', 'required' => true, 'validator' => '/[a-zA-Z]+/'));

/*
 * The process method is essential to the functionality of the form. It serves
 * various purposes:
 *  - it validates submitted data if there is any
 *  - it redirects to the success page if all the data is valid
 *  - it stores the data in the session and redirects to the form to circumvent
 *    the form resubmission problem
 */
$form->process();

/*
 * Finally, if the form is valid, dump the data (for demonstration). If it's
 * not valid (or if it hasn't been submitted yet) display the form.
 */
if ($form->validate()) {
    /*
     * Success, do something useful with the data and clear the session.
     * The getValues method returns an array of the form element values.
     */
    echo('<a href="">back</a>');
    echo('<pre>');
    var_dump($form->getValues());
    echo('</pre>');

    $form->clearSession();
} else {
    /*
     * Load the necessary scripts. jQuery, jQuery Tools and the depage-forms
     * customization.
     */
?>
<!DOCTYPE html>
<head>
    <link rel="stylesheet" type="text/css" href="../../lib/css/depage-forms.css">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
    <script src="../../lib/js/jquery.tools.min.js"></script>
    <script src="../../lib/js/effect.min.js"></script>
</head>
<body>
<?php
    /*
     * Display the form.
     */
    echo ($form);
?>
</body>
<?php
}

The validation is executed on blur by default, which means everytime you leave a specific input element. The user may only submit the form after entering valid data for all fields. 

 

Here's the live-example:  

http://docs.depage.net/depage-forms/documentation/html/js-validation_8php-example.html 

More complex validation with dependencies

More complex validations with dependencies between different input fiels are possible, but should be done with subclassing the htmlform. These will be a topic for another post. 

Next Steps

In the next posts about depage-forms we will introduce some extended features like:  

  • subdividing forms into steps and step-navigation

  • subclassing htmlform