administration mode
Pssst...Ferdy is the creator of JungleDragon, an awesome wildlife community. Visit JungleDragon

 

Article: Advanced jQuery form validation »

FERDY CHRISTANT - DEC 4, 2008 (02:11:28 PM)

One of the most common tasks of a (web) developer is to implement validation for forms. This is needed for pretty much any form, as you simply cannot trust user input. Much has been written and said about input validation already, so what is it that makes this article worthwhile for me to write and for you to read?

A few things actually. First, we will be dealing with a complex form, much more complex than the typicaly examples that you see elsewhere. Second, robustness. The complex form must work with or without Javascript, in any browser, and accept Unicode characters. Thirdly, we will be using a very cool jQuery validation plugin to make our life easier. These things combined make for quite a sophisticated form. I'm hoping this article helps you build similar forms effectively, so that you do not have to struggle the way I did.

I will focus mostly on front-end validation and dive into back-end validation where needed. Much of this article can be used for any back-end, including PHP, J2EE, .NET and Lotus Notes.

Introducing the form

As an example for this article, we'll be looking at the Jungle Dragon registration form, which is used to sign up new users:

Don't mind the basic look & feel, this form is not styled yet. It contains a number of fields and each field has some validation rules applied to it:

  • Username: Is required. Needs to be of a minimum length and cannot exceed a maximum length. Needs to be unique (in the back-end), can contain Unicode characters, except for a few characters on a blacklist.
  • Email: Is required. Needs to be in a valid email format. Must be unique in the back-end. Cannot exceed a maximum length.
  • Confirmed email: Is required and needs to exactly match the first email field.
  • Password: Is required, needs to be of a minimum length and cannot exceed a maximum length.
  • Confirmed password: Is required and needs to exactly match the first password field.
  • Agreement: Needs to be checked in order to accept the terms and conditions of the service.
  • Captcha: This form contains a custom Captcha check that needs to be passed.In another article, Building your own Captcha, you can read all about how to build one.

As mentioned before, An additional requirement is that validation must also work when javascript is disabled in the browser. With these requirements in mind, let's start to build the form.

The form markup

I will assume that you know how to build a web form, so I will only focus on the parts that matter. Let's start with the form open tag:

<form action="user/register.html" method="post" accept-charset="UTF-8" id="frmRegister">

The action attribute needs to point to your back-end script that handles the processing of the form. The method attribute indicates that we will be posting the input fields to that back-end script. The accept-charset attributes is set to UTF-8, so that we can accept Unicode text. Finally, the form ID attribute is crucial, as we will be referring to that from jQuery.

Next, let's have a look at the markup for a single field, the username field:

1. <label for="username">Choose a username</label>
2. <input type="text" name="username" id="username" value="" />
3. <label for="username" generated="true" class="error"></label>

The first line creates the label that displays the name of the field. The second line renders the actual input field. It is absolutely crucial to both name and id the field. The third and last line is an additional label that will be placed below the field as a placeholders for field-specific validation error messages. The markup of the other fields on the form work exactly like this field, so I will not go through all of them.

Finally, the markup for two buttons: the Join button and the Cancel button:

<input type="submit" value="join" />
<input type="submit" value="cancel" class="cancel" />

All standard HTML, right? Correct. There's only one thing worth mentioning. The cancel button has the "cancel" class assigned. This is a special class used by the jQuery validator plugin in order to stop validation.

Notice how we have not written a line of Javascript yet. No onsubmit event in the form, no onclick event on the button. We don't need to. jQuery will help us out.

Setting up jQuery and the validation plugin

With the form in place, it is time to setup the javascript libraries that we need. First, download the jQuery library and place it in your js folder. You will need at least version 1.2, and you can choose between a debug version or a production version. The latter has a smaller file size. jQuery in itself does not have validation features, so next we will download the jQuery validation plugin and place it in our js folder. Finally, we will create an empty js file called "frmregister.js" in the same folder. We will implement this third file in the next section. With the files in position, we need to refer to them from the HTML header of our form:

<script type="text/javascript" src="js/jquery.js"></script>
<script type="text/javascript" src="js/jquery.validate.js"></script>
<script type="text/javascript" src="js/frmregister.js"></script>

We're setup to do some coding. Let the games begin.

The front-end validation code

We've arrived at the heart of this article. It is time o implement the validation code on the front-end. Note that the validation plugin has two major ways to implement validation: declaratively and explicitly. The declarative approach let's you add special classes and attributes to the markup of your input fields. The explicit approach defines the validation rules not in the markup, but in the javascript, in our case frmregister.js. I have chosen to use the explicit approach, because I think markup should not be polluted by plugin-specific attributes.

Without further delay, I'm going to simply throw the full code at you and explain it line by line. Since the code listing is quite long, I have placed it on a seperate page. The page will open in a new window so that you can conveniently keep it next to the article. Click here to open the code listing. Below are the most important line numbers and their explanation:

1. This is the ready call of jQuery itself. All jQuery code must be placed inside this event, including our validation code.


7. This is our main call to the validation plugin's validate method. As you can see, we are using the id of the form we set earlier. The lines that follow, which is the majority of the code, indicate the various options of the validate method.


8. By default, validation routines run at every keypress, which I think is a bit over the top, especially considering we will be doing remote calls to the back-end. By setting onkeyup to false, validation only takes place upon a field exit (onblur) and upon a submit (user hitting ENTER or clicking the submit button).


9. This is the start of the rules literal, the most important part of the code. The rules literal consist of field elements at the highest level, and validation rules at the next level.


10-13. Here we are setting some validation rules for the username field. Note that the required, minlength and maxlength rules are built-in validation routines of the plugin. There are dozens of these rules available for you to use, here is the list.


14-15. These two lines are very important. They are custom validation routines. It is very easy to extend the validation plugin with your own validation rules, such as checking for illegal characters or checking if a username is unique in the back-end. Here we are simply declaring these custom rules, we will get to the implementation of them later on. Note that the order of the validation rules is also important. We want to do a char check before we will even consider doing any remote checks!


17-39. The rest of the validation rules follow the same principles as discussed. You declare the fieldname and then set the rules. Note how we have set the email field to require a valid email address (email:true) and how we are defining rules to match fields (equalTo: "email_first").


40. This is the start of the messages literal. The messages literal is used to explicitly set validation error messages per fieldname/rule combination. When validation does not pass, these individual error messages will be placed below the fields (or wherever you have positioned them in your markup). Note that these messages are optional, the plugin has built-in messages that may do just fine. I am a fan of explicit programming, so I decided to set these messages by hand.


41-70. These are the actual validation error messages. As you can see, they are organized per field and then by rule. You can simply set a static string, or if you need to include dynamic data, you can use the jQuery.format function, where %s will be replaced at runtime with the parameter(s) set in the validation rule.


Halfway down the code, let's take a small break. We have witnessed already how powerful the jQuery validation plugin is. It takes vey little code to implement complex validation rules. However, it cannot cope with every possible validation rule. Luckily, we can easily write our own. For the registration form, we will be needing three custom routines:

  • Username check. We want to check if the username entered does not yet exist in the database.
  • Email check. We want to check if the email entered does not yet exist in the database.
  • Char check. We want to check the username for illegal characters, yet still allow Unicode.

The way to do this is to use the addmethod method of the jQuery validator. Let us continue with the code:


77. Here we are defining the custom usernameCheck method. Note how we set this rule earlier for the username field at line 15. The username that is being validation will be passed to the argument "username" of our method definition.


78. For the username check, we will be doing a Ajax call to a server-side method that tells us whether the username is already in use. This line sets the URL we will use for this. It is worth mentioning that the validation plugin has a built-in "remote" rule, which means that for simple remote checks, we would not even need to write this custom method. We will do this anyway, as it gives us more control and we can learn a lot about how jQuery (not the validation plugin) works.


79. This line starts jQuery's ajax method. This is a low level method that offers the flexibility that we need. The lines that follow indicate the options that we pass to this method.


80: We do not want our remote calls to be cached, because the username check is data-driven and data may change at anytime. Therefore, we set caching to false.


81. Whenever we do a remote call, we can choose to make an asynchronous call (do not wait for the result of the remote check), or a synchronous call (wait for the result of the remote check). Because of the way the validation plugin works, we need to explicitly set it to synchronous, by setting asynchronous to false, otherwise things will not work.


82. For remote calls we need to choose whether to do a GET or POST request to the remote URL. I am setting it to "post" for two reasons. First, in a GET request we would have to pass the username via the URL. Since it can contain illegal URL characters (any Unicode) we would have to deal with encoding and decoding data in the URL. Debugging would become harder too. The second reason is personal. My back-end is Code Igniter, a PHP framework that does not accept URL parameters via query strings in GET requests. By doing a POST, we avoid both issues.


83. Here we are setting what data to POST. In our case it is simply the username that was passed to the custom validation function.


84. The URL to post to.


85-89. We will expect our method to return the result of the check in JSON format. For this case, it means it will simply output "TRUE" or "FALSE", so we will simply return that as part of the function. 


90. The last parameter of the custom validation function definition we have left empty (''). If you want to, you can set the custom validation error message here. Since we have explicitly defined this in the messages literal already, it is empty here.


92-105. This blocks checks if the email address that was entered by the user is unique in the database. It work in a similar manner as our username check function.


108-121. Finally, on to our third and last custom validation function. We want to prevent users from entering illegal characters for the username field. The simple approach is to use an alphanumeric rule. This essentially covers the range [a-z], [A-Z], and a few additional characters.  The problem with this approach is that marks any Unicode character outside the Latin1 range as illegal, which is not what we want. Instead, we will want to allow all Unicode characters, expect for a few illegal characters on a blacklist. 


This completes our front-end validation code. The good news is that this code can easily be integrated into any back-end. Whilst we have mostly focused on getting things to work, there is a wealth of additional power and options available in jQuery and the validation plugin to further enrich our form. Now, on to the bad news.

Back-end validation

The purpose of the code discussed in the first part of this article is to make validation and its feedback rich and fast, by preventing page refreshes. It does not replace back-end validation however:

  • In case a user has javascript disabled, validation must still take place.
  • Spammers may post to your forms using a script, completely bypassing your front-end validation.

Unfortunately, this means that we pretty much have to duplicate the validation rules in our back-end. If you would add database constraints into the mix, there are in fact three layers at which we are doing the validation. Since this article was written with any platform in mind, I can only give you some general clues on the things that matter in the back-end:

First, the easy part. There is no need for us to check if the user has javascript enabled. If it is disabled, the submit button we defined will still do its work: it will submit to the back-end.

Our back-end, which is the URL we are posting to, will receive the form values from the request and has to run the same validation rules as the front-end validation. In an ideal situation, both the front-end and back-end can share the validation rule and message declarations, but this greatly depends on your platform and back-end validation library. Otherwise, you will have to duplicate the rules and messages, or you have to build some glue code. 

As said, the implementation of the back-end validation differs per platform. For the sake of example, here is how I am doing it in PHP, using Code Igniter's FormValidation library:

$this->load->library('form_validation');
 
// setup validation rules
$this->form_validation->set_rules('username', 'username', 'trim|required|min_length[5]|max_length[45]|
callback_char_check|callback_username_check');
$this->form_validation->set_rules('email_first', 'email address', 'trim|required|max_length[255]|
valid_email|callback_email_check');
$this->form_validation->set_rules('email_second', 'confirmed email address', 'trim|required|max_length[255]|valid_email|
matches[email_first]');
$this->form_validation->set_rules('password_first', 'password', 'required|min_length[6]|max_length[128]');
$this->form_validation->set_rules('password_second', 'confirmed password', 'required|min_length[6]|
max_length[128]|matches[password_first]');
$this->form_validation->set_rules('tos', 'in order to join, agreeing to the Terms and Conditions', 'required');
 
// run the validator
if ($this->form_validation->run() == false)
{
// error handling code
}

As you can see, the way rules are defined is similar to the front-end code. Validation messages are defined in a language file however.

On to the next part: user feedback. Assuming that we have the back-end validation working, we need to provide the user with feedback. This consists of two parts: field preservation and error messages. In the front-end validation scenario, all values entered by the user are preserved upon validation, because the submit to the server has not really happened yet. In the back-end scenario, we need to explicitly capture the values that the user has entered and pass it back to the form when we reload it, but only if validation has failed. Typically this is an easy thing to do: we pass the post variables back to the form, and change the form markup so that the value attributes of the input fields get these values assigned. Here's a PHP example:

<input type="text" name="username" id="username" value="<?= $username;  ?>" />

The second part concerns error messages. In the front-end validation, we positioned field-specific error messages using labels in the markup. We will want the messages that are part of the result of the back-end validation to use these same labels. In most cases, this will me a matter of passing the field errors to the markup and filling the label with the specific message:

<label for="username" generated="true" class="error"><?php echo form_error('username'); ?></label>

With this in place, we now have a consistent user experience: the rules, messages and styling are exactly the same in the front-end and the back-end. Now, let's have a look at a few more things to make it more robust.

First, the back-end validation code will receive its parameters via POST variables. You cannot trust these blindly, you will need to santize these variables to prevent XSS attacks, SQL injection and all those other goodies of the web. My only advise here is to find a good library that does this for you. In my case, the Code Igniter framework takes care of this:

$this->input->post('country')

By accessing the post variable this way, it is automatically sanitized.

Now, let's have a word about the remote checks we used in the front-end validation code. They were used to check if a username or email address entered by the user was unique in the database. In our back-end logic, we write the database check methods only once. For back-end validation, we call it directly. For front-end validation, we can provide a JSON wrapper method that calls the database check. Why the additional wrapper method? For the database check method we will want true/false returned, whilst the remote calls expect a JSON response, which means printing (not returning!) "true" or "false" to the HTTP response. 

As if life is not complex enough already, a word of warning applies to these database check methods. The email checker, for example, is called remotely to check if an email address exists in the database. It will return "TRUE" if this is the case. A brute force remote dictionary attack may reveal a lot of confirmed email addresses to spammers, so be careful. It goes too far for this article to explain how to close this leak, but I can tell you this: don't solve it in your application, solve it at the web server level. There, you can configure IP blacklists, set request tresholds, etc. Coding these things in our application introduces unwanted complexities and a maintenance nightmare.

Conclusions

I hope this article helps you in building advanced, robust, and consistent forms. As you can see, even with the best of libraries, it is still a lot of work. Writing this article was a lot of work as well, so please provide your feedback and rating below :)

Note: you might also like my "Building your own Captcha" and "Building Unicode LAMP Applications" articles.

Share |

Comments: 34
Reviews: 15
Average rating: rating
Highest rating: 5
Lowest rating: 4

COMMENT: TOCHIE rating

DEC 14, 2008 - 02:44:01 PM

comment » Very good tutorial on how to start off! I'v been looking for this all day....now i can get to work...

Thanks dude. «

COMMENT: TOCHIE email

DEC 14, 2008 - 03:13:25 PM

comment » Please I need some help here. What happens if you want to place all the error messages in a DIV box and place on top of the form?

Thanks «

COMMENT: FERDY

DEC 15, 2008 - 11:17:50 AM

comment » Tochie,

This should be easy enough, just check the documentation:

http://docs.jquery.com/Plugins/Validation/Validator

Or the forum:

http://groups.google.com/group/jquery-en?pli=1

I hope this helps,

Ferdy «

COMMENT: S VIDYASAGAR rating

JAN 7, 2009 - 05:50:57 AM

comment » It's a great article for beginners. Thank You. «

COMMENT: MITCH emailhomepagerating

JAN 19, 2009 - 17:45:23

comment » Great article - just got to sit down and digest it all now! «

COMMENT: DAVID emailhomepage

FEB 13, 2009 - 04:08:47 PM

comment » Great article. Fantastically clean implementation of jQuery.

One question: I'm curious as to what the server-side implementation of the 'usernameCheck' looks like. I'm using php, and I would google for it, but as I'm new to AJAX, and there seems to be several methodologies, I'm not sure where to start.

What does the server side "POST" code.

Thanks,

David «

COMMENT: FERDY

FEB 16, 2009 - 08:29:35 AM

comment » David,

The reason why I'm not showing the post code is that it is completely different for each application. In my case, usernameCheck is simply a PHP function. It checks from the post data the username to check for, does a lookup in the database, and then echoes "true" or "false" depending on the outcome. Note that such a function should not return true of false, it should ECHO it.

Does that help? «

COMMENT: HANKS email

MAR 9, 2009 - 04:40:03 AM

comment » My problem is "the CI validation is not working when you include aweber form at the registration form".Especially when you use specific fields validation. Can you show us how to implement without using the "CI validation". Just for the form+jquery+ci_php_usercheck.

*****username_check validation****

anyways, thanks for this. It helps a lot. «

COMMENT: AA homepage

MAR 26, 2009 - 07:33:51 AM

comment » aaaaaaaaaaaaaaaaa «

COMMENT: PP

MAR 26, 2009 - 09:49:23

comment » Absolutely perfect! Works like a charm!

Would be 12/10 if there was a live simplified demo, of the form, of some sort... but other than that... Thanks loads! «

COMMENT: RAMMOHAN emailrating

APR 6, 2009 - 08:24:24 AM

comment » Its really a nice explanation for startup...Thank You :-) 21 «

COMMENT: MAHESH BISEN emailhomepage

MAY 26, 2009 - 11:56:32 AM

comment » 20 Perfect for me «

COMMENT: RUDI emailrating

JUL 2, 2009 - 10:50:40 PM

comment » Very nice tutorial indeed. I found it very helpful. I have done a few form validation scripts and nothing matches the beauty of this. I will definitely use this in the future. I do prefer to do my own back end scripts though instead of a library.

Thanks for the hard work putting this together. 01 «

COMMENT: MATT homepagerating

SEP 10, 2009 - 10:56:57

comment » Not much to add to this post, everything is crystal clear and well formatted.

Keep up the good work ! «

COMMENT: FTI emailhomepage

SEP 12, 2009 - 21:53:45

comment » thank. this will be helpful to me to improve myself. 01 «

COMMENT: NICK email

OCT 8, 2009 - 10:45:10

comment » Ferdy,

Great article...

I started using jQuery a month or so ago in a Domino project (I'm using autocomplete, Dialog boxes, AJAX\ JSON, etc, so thought I was getting thre hang of jQuery. I've been trying to use the jQuery.validator, but can't seem to get it to work. I have created a really simple Notes form, one field: email, a submit button, and in JS Header:

$(document).ready(function() {

// do stuff when DOM is ready

$("#_v3").validate({

debug: true,

rules: {

email: "required"

}

});

});

My form name is v3, which when Domino serves up becomes _v3. I keep getting "nothing selected, can't validate, returning nothing" in the console on form load, which leads me to believe it can't get a handle on the form...? If I just use a test variable, like var test = $("#_v3"); it correctly gets the form object. When you submit, it just submits form. I must not be initialising the validator correctly.

I must be missing something really simple. Any help would be much appreciated.

Regards,

Nick «

COMMENT: SHIRLEY email

OCT 8, 2009 - 12:51:10 PM

comment » Hi,

hey you should highlight the demo link or show somewhere... 29 «

COMMENT: RUDI10 emailhomepagerating

DEC 18, 2009 - 10:14:57 AM

comment » Nice work

I like it 01 «

COMMENT: BRYAN emailhomepagerating

APR 8, 2010 - 10:07:45 PM

comment » Hey man... great tutorial... I think I have most of it working except for the json_username_check.php file... I have it echoing "TRUE" or "FALSE" depending on whether the username is available or not, but the validation isn't working. I was wondering if you could help out a bit.

I'm using the code that you used pretty much verbatim, except that I added ".php" to the URL of the script that checks the DB... Here's my PHP file.

It works fine when I test it, but for some reason, the ajax isn't working in my form...

HEre's my PHP file:

$username_to_check = $_POST['username'];

include("conn.php");

$query="SELECT username FROM members WHERE username = '$username_to_check'";

$result=mysql_query($query);

mysql_close($con);

if (mysql_num_rows($result) == 0) { echo "TRUE"; } else { echo "FALSE"; }

Thanks again for the great tutorial!

-Bryan «

COMMENT: VIKTOR emailrating

APR 10, 2010 - 07:41:23 PM

comment » Thank you FERDY, I found this tutorial very helpful, keep up your good work! «

COMMENT: MAJID emailrating

OCT 4, 2010 - 06:09:29 PM

comment » This is really good stuff. Especially the remote checks which is too brief in the documentation. «

COMMENT: FLORIAN email

NOV 28, 2010 - 23:15:02

comment » Hello,

I am realy happy that I have found your tutorial, but i want to ask u, if you could please tell me how your controller looks like?

I have the problem, that the script is allways true!

Thx anyway «

COMMENT: PANKAJ homepage

DEC 17, 2010 - 11:20:33 AM

comment » aaaaaaaaaaaaaaaa «

COMMENT: MOHSEN rating

DEC 18, 2010 - 09:19:26 AM

comment » thank you so much «

COMMENT: IGOR email

MAR 27, 2011 - 07:41:16 AM

comment » I have a question. Is it possible to display OK icon if field passed validation? «

COMMENT: HARDIK CHAVDA email

MAY 11, 2011 - 05:35:47 AM

comment » rules: {

reg_name: {

required: true,

noSpace: true,

remote:{

url:"../modules/val_new_user.php",

type:"post",

data:{

name1: function() {

return $("#name1").val();

}

}

}

},

messages: {

reg_name: {

required: "Please enter your name!",

remote: "User Name already exist!"

}, 26 26 26 26 «

COMMENT: DAVE

MAY 11, 2011 - 09:25:15 AM

comment » Thanks for this ! «

COMMENT: PURIST email

AUG 28, 2011 - 02:37:40 AM

comment » Thanks for the good work !!

Could you please make it PERFECT and display the php part ??

'cos I can NOT make it work with mine !!!

Thanks in advance «

COMMENT: MEMTECHLODHI emailrating

SEP 24, 2011 - 04:07:40 PM

comment » Hello Everyone,

In JQuery blur method trigger blur event when element will lose their focus. In this article I am using blur () method on html page. In html page I had created some text boxes, if any textboxes got focus then back color of textboxes will white and if textboxes lost their focus then textboxes back color will change............................... for more details please check out this link.

http://mindstick.com/Articles/db2a3600-a3a2-402d-86d1-0c290e451efa/?JQuery%20blur%20method

Thanks !!!!!! «

COMMENT: TOEKANG WEB rating

NOV 9, 2011 - 02:41:27 AM

comment » Thank a lot «

COMMENT: SYED MOHAMMED AHMED emailhomepage

NOV 9, 2011 - 11:45:44 AM

comment » ide and seek form validation using jQuery

http://wp.me/p1Wsov-2l «

COMMENT: TECHIEDAN emailhomepagerating

DEC 5, 2011 - 05:40:33 AM

comment » Superb. I was looking into form validation and this is one of the best examples I have seen.

Thank you very much «

COMMENT: JOSEPH BUARAO emailhomepage

JAN 19, 2012 - 05:21:13 AM

comment » awesome tutorial.. «

COMMENT: JEFFERSON emailrating

JUL 30, 2013 - 06:58:14 AM

comment » how can I have validation for the check box???

condition: The form is accepted if and if only the check box is checked. «

RATE THIS CONTENT (OPTIONAL)
Was this document useful to you?
 
rating Awesome
rating Good
rating Average
rating Poor
rating Useless
CREATE A NEW COMMENT
required field
required field HTML is not allowed. Hyperlinks will automatically be converted.