Form Validation

I've been playing with some form validation stuff for CF. I had been usign , but I wanted the HTML interface to act a bit more like the Flash interface, but I don't really want to use Flash. I've also been doing a lot more work with some of the DHTML libraries that AJAX has made popular, so I figured there had to be a relatively elegent way to do form validations with something like Ajaxian about easy form validation and decided to give it a try. The article on Dexagogo shows how they created a library to handle form-validations that doesn't require any other work than creating a form. This was just what I was looking for!

Basically, you just need the latest files from script.aclo.us with the latest prototype version (the 1.5 release candidate is included in the latest script.aculo.us lib folder), and the validation library. Convienently, they're all included in the demo file on the site.

To use this, you really only need prototype and the validation library (script.aculo.us adds a nice effect – much like the Flash format in cfform). For me, I made these calls:

<head>
   <script type="text/javascript" src="/scripts/scriptaculous/lib/prototype.js"></script>
   <script type="text/javascript" src="/scripts/validator.js"></script>
   <script type="text/javascript" src="/scripts/scriptaculous/scriptaculous.js?load=effects"></script>
</head>

This is slightly different than the example on their page; they load the effects.js file directly, I'm calling the library via script.aculo.us with the load parameter. This isn't really a big deal for one library, but it is convenient when you want to use several, but not all, of the libraries (e.g. scriptaculous.js?load=effects,dragdrop,slider).

Anyway, to actually use this, you need to create a form with an id attribute:

<form name="feedback" id="feedback" action="#cgi.script_name#" method="post">
...
</form>

Now, we add some fields and use the class attribute to call the validator:

Name: <input type="text" name="name" id="name" class="required" /><br/>
Email: <input type="text" name="email" id="email" class="required validate-email" />
<input type="submit" />

There are 11 options for use in the validation library (this is directly off their page):

  • required (not blank)
  • validate-number (a valid number)
  • validate-digits (digits only)
  • validate-alpha (letters only)
  • validate-alphanum (only letters and numbers)
  • validate-date (a valid date value)
  • validate-email (a valid email address)
  • validate-url (a valid URL)
  • validate-date-au (a date formatted as; dd/mm/yyyy)
  • validate-currency-dollar (a valid dollar value)
  • validate-one-required (At least one textbox/radio element must be selected in a group)

This is really nice, because if you want to allow an optional field, but validate it, you can do:

<input type="text" name="email" class="validate-email" />

There's one more piece of the pie...to call the validation library. At the bottom of your page add:

<script type="text/javascript">
   new Validation('feedback', {immediate:true});
</script>

The first argument is the id attribute of the form you're wanting to validate. The second tells the Validator object what to do. This particular example enables validation on each field as you leave it (which I find useful). Some of the other options are:

  • stopOnFirst (boolean): Stop on the first validation failure; default: false
  • onSubmit (boolean): Override the default behavior of adding an even listener to the onsubmit event (set to false if you want to make sure your onsubmit method gets called no matter what); default: true
  • immediate (boolean): validate when the cursor leaves the field; default: false
  • focusOnError (boolean): place the focus on the first field with an error; default: true
  • useTitles (boolean): make field validators use form element title attributes as error advice message; default: false
  • onFormValidate (string function): call a function when the form is validated
  • onElementValidate (string function): call a function when an element is validated

What I thought was really cool was the ability to add custom validation types via an API. Say you only want folks to use capital letters for their names, you simply add a new validation type like:

<script type="javascript">
   Validation.add('validate-ucase', 'Please only use upper-case letters (A-Z) in this field.', function(v){
      return Validation.get('IsEmpty').test(v) || /^[A-Z]+$/.test(v);
   }
</script>

Want to add several? You can do that too:

<script type="javascript">
   Validation.addAllThese([
      ['validate-lcase', 'Please only use lower-case (a-z) letters in this field', function(v){
         return Validation.get('IsEmpty').test(v) || /^[a-z]+$/.test(v);
      }],
      ['validate-zip', 'Please check your zip code', function(v){
         return Validation.get('IsEmpty').test(v) || /^(\d{5})(( |-)?(\d{4}))?$/.test(v);
      }],
      ['validate-phone', 'Please check your phone number', function(v){
         return Validation.get('IsEmpty').test(v) || /^(([0-9]{3}-)|\([0-9]{3}\) ?)?[0-9]{3}-[0-9]{4}$/.test(v);
      }],
      ['validate-ssn', 'Please check the Social Security Number. It should follow the format 999-99-9999', function(v){
         return Validation.get('IsEmpty').test(v) || /^([0-9]{3}(-?)[0-9]{2}(-?)[0-9]{4})$/.test(v);
      }],
      ['validate-ip', 'Please check the IP address', function(v){
         return Validation.get('IsEmpty').test(v) || /^(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])$/.test(v);
      }],
      ['validate-uuid', 'Please check the UUID', function(v){
         return Validation.get('IsEmpty').test(v) || /^[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{16}$/.test(v);
      }],
      ['validate-guid', 'Please check the GUID', function(v){
         return Validation.get('IsEmpty').test(v) || /^[0-9a-f]{8,8}-[0-9a-f]{4,4}-[0-9a-f]{4,4}-[0-9a-f]{4,4}-[0-9a-f]{12,12}]$/.test(v);
      }],
      ['validate-float', 'Please only use floating point numbers in this field', function(v){
         return Validation.get('IsEmpty').test(v) || /^(\b[0-9]+\.([0-9]+\b)?|\.[0-9]+\b)$/.test(v);
      }],
      ['validate-visa', 'Please check your credit card number', function(v){
         return Validation.get('IsEmpty').test(v) || /^4\d{3}-?\d{4}-?\d{4}-?\d{4}$/.test(v);
      }],
      ['validate-mastercard', 'Please check your credit card number', function(v){
         return Validation.get('IsEmpty').test(v) || /^5[1-5]\d{2}-?\d{4}-?\d{4}-?\d{4}$/.test(v);
      }],
      ['validate-discovery', 'Please check your credit card number', function(v){
         return Validation.get('IsEmpty').test(v) || /^6011-?\d{4}-?\d{4}-?\d{4}$/.test(v);
      }],
      ['validate-amex', 'Please check your credit card number', function(v){
         return Validation.get('IsEmpty').test(v) || /^3[4,7]\d{13}$/.test(v);
      }],
      ['validate-diners', 'Please check your credit card number', function(v){
         return Validation.get('IsEmpty').test(v) || /^3[0,6,8]\d{12}$/.test(v);
      }],
      ['validate-time', 'Please only use time in this field', function(v){
         return Validation.get('IsEmpty').test(v) || /^\d{1,2}[:]\d{2}([:]\d{2})?( [aApP][mM]?)?$/.test(v);
      }]
]);
</script>

This should be all of the normal items included in (plus a couple extra for good measure). Now the only thing left is to make it look pretty. One of the nice things about the Flash format in is that it color codes required fields with the different halo effects. To obtain a similar effect in the forms, we'll use style sheets instead.

This is a rather light stylesheet, but it'll give you something to start with (based on the default haloGreen skin):

input.required, textarea.required {
   border: 1px solid #ffbf2b;
}
input.validation-failed, textarea.validation-failed{
   border: 1px solid #ff3300;
   color: #ff3300;
}
input.validation-passed, textarea.validation-passed{
   border: 1px solid #00cc00;
   color: #000;
}
.validation-advice {
   margin: 5px 0;
   padding: 5px;
   background-color: #FF3300;
   color: #fff;
   font-weight: bold;
}
.custom-advice {
   margin: 5px 0;
   padding: 5px;
   background-color: #c8aa00;
   color: #fff;
   font-weight:bold;
}
I made a short example of some of the validations at http://swem.wm.edu/blogs/waynegraham/examples/validation/. I have to say that I've found this to be a bit better solution (at least for my needs) than using !

Comments (Comment Moderation is enabled. Your comment will not appear until approved.)
Rajeev G's Gravatar Your Documentation is good. Thanks , it helped me a lot. I wish to add a validation method on validation.js.

I have a field in my form recipient emails for sending a message to the recipients specified. In that case I have to check the format of each email id separated by commas. I found no method anywhere with java script. Thanks in advance
# Posted By Rajeev G | 1/12/07 5:32 AM
Vashisht's Gravatar Hi Wayne

Could you please guide me like how to add validation to radio or checkbox button, please guide.

thanks
Vashisht
# Posted By Vashisht | 1/30/07 4:54 AM
rakesh's Gravatar Hi Wayne

Just get it, it is very simple, i tried myslef and get the way...

thanks
# Posted By rakesh | 2/18/07 11:55 PM
daROOK's Gravatar Hi Wayne,
I've been trying like crazy to get the validate-one-required
validation to work on a radio group. I've set div's around the
radio group and put the class="validate-one-required" in the
last radio selection. It then only validates the radio button
that has the specific class declaration in it.
I've tried just about everything and I still can't get it to
validate the group as opposed to just the last radio button.
I've even debugged a bit to ensure that the div is recognized
as the parent element by the DOM: it is.

Here is an example of the radio group I'm working with:

<div>
<input class="defaultWidth" type="radio" name="reqType" id="reqTypeHW" value="Hardware"
   onClick="toggleDisplay(event,'hwSection',true),toggleDisplay(event,'swSection',false)" />Hardware 
<input class="defaultWidth" type="radio" name="reqType" id="reqTypeSW" value="Software"
   onClick="toggleDisplay(event,'swSection',true),toggleDisplay(event,'hwSection',false)" />Software  
<input class="defaultWidth" type="radio" name="reqType" id="reqTypeBoth" value="Hardware and Software"
   onClick="toggleDisplay(event,'hwSection',true),toggleDisplay(event,'swSection',true)" />Both
</div>

Any suggestions or help would be greatly appreciated.
Thanks,
# Posted By daROOK | 3/16/07 7:48 PM
closet organizers's Gravatar Affordable closet organizers for fast closet storage solutions. Design and order online. Closet are pre-assembled. Most orders are shipped the next business day.
# Posted By closet organizers | 3/17/07 8:52 AM
Kris's Gravatar Hi Wayne,

This looks great! Any test on how it will affect search engines, most do not like Flash or Javascript as much as HTML.
# Posted By Kris | 3/17/07 11:24 PM
daROOK's Gravatar Hi Wayne,
I sent a message on Friday asking about radio group
validation. I was able to create a resolution that
doesn't require the use of div tags (or other parent
node encapsulation of the buttons). I've seen some
out there that had this problem, but no resolutions.
Hope this helps:

Validation.add('validate-radio-group', 'Select one of the radio buttons above.', function(v,elm) {
var tmp = eval('elm.form.' + elm.name);
if (tmp) {
for (var i = 0; i < tmp.length; i++) Validation.reset(tmp[i]);
return $A(tmp).any(function(elm){
return $F(elm);
});
}
});

Assign the 'validate-radio-group' class name
to all in that radio group. And it one error
per radio group and updates the group if
changes occur.
-daROOK
# Posted By daROOK | 3/19/07 3:25 PM
Wayne Graham's Gravatar Thanks daRook!
# Posted By Wayne Graham | 3/19/07 3:52 PM
Wayne Graham's Gravatar Kris,

I'm not sure what you're asking...since these are for form interactions, it should have no affect on spidering...it degrades to normal form actions (get/post) if there's no JS.
# Posted By Wayne Graham | 3/19/07 3:54 PM
Dave's Gravatar Thanks Wayne for the script, it's very useful!
For the required select boxes validation to work, i had to update the test function like that :

//Ajout pour validation des select box (vérifie si index != 0)
if(elm.type.toLowerCase() == "select-one"){
toTest = $F(elm) == '0';
}
else{
toTest = !v.test($F(elm), elm);
}
if(Validation.isVisible(elm) && toTest) { ...}

Maybe it could help someone...
Any better solution is welcome :)
# Posted By Dave | 8/17/07 11:56 AM
Derric's Gravatar Information I found on your blog was very useful for making my research paper yesterday. I'm here to say Thank You very much!
# Posted By Derric | 11/23/07 1:48 PM
Daniel's Gravatar I'm curious about integrating a captcha device (php) with validation.js. You seem to do this in this comment form itself. Another approach I thought might be useful is to disallow urls (http://) in a new validation type, or more than 1 url. Any thoughts?
# Posted By Daniel | 4/24/08 12:28 PM
Wayne Graham's Gravatar @Daniel

That's really just another regex rule (which is one of the beauties of this script). You may also want to check out the latest code from http://tetlaw.id.au/view/javascript/really-easy-fi... There's also a Google Group for this now at http://groups.google.com/group/dexagogo. Definitely worth checking out!
# Posted By Wayne Graham | 4/25/08 9:52 AM