de­page-forms: val­i­da­tion of html5 forms (Part II)

, by Frank Hel­lenkamp

Val­i­da­tion of HTML form data

Thanks to the new HTML Stan­dard and the WHATWG Group it is eas­i­er than be­fore to have Browsers show stan­dard er­rors when a user does not pro­vide valid data in­side an input el­e­ment. Un­for­tu­nate­ly this only works in newer Browsers, and not in older ones (e.g. In­ter­net Ex­plor­er 8). 

 

To make it eas­i­er for de­vel­op­ers, de­page-forms pro­vides an way easy way to add val­i­da­tion to forms that works in all three dif­fer­ent places at the same time: 

  • on the serv­er
  • in the brows­er, based on the new html stan­dard
  • in the brows­er, based on javascript

This is a part of the on­go­ing se­ries about de­page-forms

Stan­dard Input El­e­ments

There are var­i­ous stan­dard input el­e­ments that are part of the HTML stan­dard and will be val­i­dat­ed by the brows­er. E.g. input[type=email] and input[type=url]. Other input el­e­ments are pre­sent­ed with a dif­fer­ent user in­ter­face or as na­tive con­trols like input[type=num­ber], input[type=range] or input[type=date]

 

de­page-forms uses these in­puts but ex­tends and en­hances the be­hav­iour in var­i­ous places. 

Re­quired Fields

The most sim­ple case for val­i­da­tion hap­pens when an input is re­quired

/*
 * 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,
));

Val­i­da­tion based on type

de­page-forms also val­i­dates based in the in­put-type. And you can pro­vide an op­tion­al er­ror-mes­sage that will be dis­played, in case the user does not pro­vide 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",
));

Val­i­dat­ing num­ber with min/max val­ues

For num­bers there is the spe­cial case of min­i­mum and max­i­mum num­bers: 

/*
 * 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,
));

Val­i­da­tion based on reg­u­lar ex­pres­sions

The next way to val­i­date val­ues are reg­u­lar ex­pres­sions. These in­puts will be val­i­dat­ed on the serv­er and also in newer browsers that un­der­stand the pat­tern-at­tribute. 

/*
 * 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]+/',
));

Val­i­da­tion with clo­sures

In­stead of val­i­da­tion with a reg­u­lar ex­pres­sion, you may also pro­vide a clo­sure func­tion to val­i­date the input value. The clo­sure func­tion will only be val­i­dat­ed on the serv­er, 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;
        }
    },
));

Dif­fer­ence to the HTML stan­dard

There is one im­por­tant case where de­page-forms be­haves dif­fer­ent­ly from sim­ple html-in­puts: Check­box­es. 

 

In HTML5 if a check­box is re­quired, every re­quired check­box in a set has to be checked to val­i­date. In de­page-form the boolean field works the same way. If it is re­quired, you have to check it. 

 

But if you use the in­put-mul­ti­ple with the check­box skin, the user only has to check one check­box of a set to pass val­i­da­tion (anal­o­gous to the ra­dio-but­tons/in­put-sin­gle). 

Javascript Val­i­da­tion

For Browsers that don't sup­port the di­rect val­i­da­tion of input fields or to dis­play the er­ror-mes­sages di­rect­ly, we can ac­ti­vate the val­i­da­tion with javascript. We have to in­clude jQuery, the jquery-tools and the effects.​js into the html-code. 

 

Here a full ex­am­ple: 

<?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 val­i­da­tion is ex­e­cut­ed on blur by de­fault, which means every­time you leave a spe­cif­ic input el­e­ment. The user may only sub­mit the form after en­ter­ing valid data for all fields. 

 

Here's the live-ex­am­ple:  

More com­plex val­i­da­tion with de­pen­den­cies

More com­plex val­i­da­tions with de­pen­den­cies be­tween dif­fer­ent input fiels are pos­si­ble, but should be done with sub­class­ing the html­form. These will be a topic for an­oth­er post. 

Next Steps

In the next posts about de­page-forms we will in­tro­duce some ex­tend­ed fea­tures like:  

  • sub­di­vid­ing forms into steps and step-nav­i­ga­tion
  • sub­class­ing html­form