2010
07.24

Again another long time between posts, this one is partly a small tutorial and partly about a small issue I encountered and workaround. This post discusses form validation using a cool jQuery form validation plugin created by Jörn Zaefferer, which I highly recommend, you can download the plugin from here. The plugin allows you to quickly and easily validate your html forms using the power of jQuery, the basic principle is that you specify the rules for validation on the fields of your form and submitting the form will be disabled until all fields are valid, where validation rules are broken the user is informed with messages next to the invalid fields. I wouldn’t be surprised if this plugin became part of jQuery directly since so many people are using it already.

Lets have a look at a quick simple example, lets say I have a form with 3 input fields, name, email and website, we want to have the name and email fields required, we want to check the email is valid and because we are storing these fields in a database with a character limit we need to check the fields are not too long. Below is the html form code and the javascript for the validation.

<script type="text/javascript">
$(function(){
    $("#subscribe_test").validate({
        rules: {
            fullname: { required: true, maxlength: 64 },
            email: { maxlength: 32 },
            website: { maxlength: 32 }
        }
    });
});
</script>

<form id="subscribe_test" action="save_subscriber.php" method="POST">
  <table>
    <tbody>
      <tr>
        <td><label for="fullname">Full name: *</label></td>
        <td><input id="fullname" type="text" /></td>
      </tr>
      <tr>
        <td><label for="email">Email: *</label></td>
        <td><input id="email" class="email required" type="text" /></td>
      </tr>
      <tr>
        <td><label for="website">Website:</label></td>
        <td><input id="website" type="text" /></td>
      </tr>
      <tr>
        <td><input type="submit" /></td>
        <td></td>
      </tr>
    </tbody>
  </table>
</form>

In the above example you can see that you can apply the validation rules both in javascript and also using the predefined rule names as the css class for the input. E.g. the email input field is using classes email and required, the validation plugin will look for any class names on the inputs and apply the validation rule if there is one. I could have defined the email rule solely in the script but I wanted to show that there is a quicker way using classes. The working example for the above code is below.

You can also do remote validation. For example, lets say in our example we did not want someone with the same email address to be subscribed twice. You can use a special validation rule remote which points to a script which should output true or false based on the form input value. We will also give a special message for when the email address is already in use. The changed script code is then:

<script type="text/javascript">
 $(function(){
     $("#subscribe_test2").validate({ rules: {
         fullname: { required: true, maxlength: 64 },
         email: { maxlength: 32, remote: "/check_subscribed.php" },
         website: { maxlength: 32 }
     },
    messages: {
        email:{ remote: "Already subscribed" }
    } });
 });
</script>

The running example now will not allow you to enter the email test@example.com, for this example there is a script called check_subscribed.php which is hard coded to look for the POST email variable and return false if it equals test@example.com.

So that is all good everything seems to be validating fine. Now I will show you a small case to watch out for. Lets assume that the subscribe form needs to be submitted using ajax and only accepts a required email address which should be remotely validated. Below is the code and the working example, if you simply enter the already subscribed email test@example.com and submit you see it does not work properly, the form gets submitted even though the validation fails.

Update 29/09/2010 since updating this post and rechecking the code it appears, this actually does work. Perhaps the browsers have changed the order the javascript events occur, I certainly did not change anything, this was an issue previously.

Code and example below.

<script type="text/javascript">
jQuery(function($){
       $("#subscribe_test3").submit(function(e){
          if ($(this).valid()){
               $.ajax( {
                   type: "POST",
                   url: "/save_subscriber.php",
                   data: "email="+$("#subscribe_test3_email").val(),
                   success: function(data){
                        $("#submit_result").html("Ajax submit results:
"
+ data);
                   }
               });
          }
          return false;
    });
    $("#subscribe_test3").validate({ rules: {
         email: { maxlength: 32, remote: "/check_subscribed.php" }
     }, messages: {
        email: { remote: "Already subscribed"}
     }
     });
});
</script>

<form id="subscribe_test3" action="save_subscriber.php" method="POST">
  <table>
    <tbody>
      <tr>
        <td><label>Email: *</label></td>
        <td><input id="subscribe_test3_email" class="email required" name="email" type="text" /></td>
      </tr>
      <tr>
        <td><input type="submit" /></td>
      </tr>
    </tbody>
  </table>
</form>

The reason the above example did not work properly is because the remote validation checking is done asynchronously, as is the ajax request. In the above code, the form submit event binding function checks first if the form is valid before doing the ajax submit. The trouble is that the remote validation is done asynchronously. So the valid check is just returning true instead of false. In order to solve this the remote validation needs to be done synchronously instead (or async: false). Below is the relevant fix and the fixed example.

$("#subscribe_test3").validate({
  rules: {
    email: {
      maxlength: 32, remote: { url: "/check_subscribed.php", async: false }
    }
  },
  messages: {
    email: { remote: "Already subscribed"}
  }
});

Update 27/09/2010

It has been asked what the check_subscribed.php script did, so here it is below:

<?php
$email = $_REQUEST["email"];
if ($email == "test@example.com"){
    echo "false";
} else {
    echo "true";
}
?>

Update 01/11/2010

Someone has asked for the files used in these examples, so here is a zip file containing a html page and the necessary php scripts. The jquery and validation plugin are not included in the zip but are referenced as external scripts. This is a recommended way of including jQuery in your sites (but obviously a more up to date version).

21 comments so far

Add Your Comment
  1. Nice tutorial…
    but i have a problem with the remote validation

    how’s the check_subscribed.php should be..?
    help please :)

  2. its fine for adding a new record but how to use for update the record

  3. That’s a php question I guess. It completely depends on what your requirements are. The script above used hard-coded true or false responses, but in reality you would check your database to see if the email was already taken by querying by the email address. If you find any records you would return false. If you are editing an existing record you probably need an additional check that the email address doesn’t belong to the record you are attempting to edit.
    The remote URL can take query parameters so you could send the record id to the server to validate the email. You can also specify a POST data for the remote validation e.g.
    remote: { url: “/check_subscribed.php”, async: false, data: { id: “1″, usergroup: “2″ } }

  4. hi it is very nice tutorial and i was searching it.but my jquery files are not supporting this tutorial so it will be great if you can create a downloadable zip file of this tutorial.
    i am waiting for your response,Thanks a lop

  5. great post, thanks for sharing

  6. Hi thanks for the great tutorial.
    I have another similar scenario with a twist.
    I have a field called title, with a remote check that checks for similar titles in the database.
    It works perfectly like you did it in here. And it shows the error message too. However, I actually just want to show the error message or warning, and still be able to submit the form even tho this validation failed.
    I want to allow same titles, but just show a warning to the user when he is doing so.
    Do you know how I can go about doing this?

    Thank you

  7. Hmmm, just checking the documentation for the validation plugin, it appears you can set your own form submit function, which I suppose you could check whether the form or individual elements were valid and then submit the form anyway. See here http://docs.jquery.com/Plugins/Validation#General_Guidelines it advises to use this:

    $("#myform").validate({
     submitHandler: function(form) {
       form.submit();
     }
    });

    You can validate individual elements programatically using:

    $("#myform").validate().element( "#myselect" );

    So in the submit function you could make the sure the errors/warnings are displayed and then use the native form submit function to submit it anyway. Hope that helps.

  8. Download file don’t exist any more!

  9. Thanks for letting me know, the download link is working again.

  10. Thanks for this detailed tutorial, it got me up and validating in a flash!

    I found one anomaly, however, that I hope you can help with. Using the code below, it seems that no standard email type validation is occurring before performing the ajax request. This results in all error messages stating that the user already exists, rather than identifying a mis-formed address.

    So, whether the user types jimmy@micros, jjj.micros, or any other invalid address, the ajax call is performed, and the user is warned that the email has already been registered. So, in a nutshell, Is there a way to perform standard validation BEFORE the ajax request?

    email: { required: true, email: true, minlength: 3, remote: “checkemail.php” , async: false },

    Thanks again for your quick and easy to follow post!

  11. Jim, thanks for the nice comments. I believe you might be referring to the issue identified in the post. I noticed that this would happen to me when I filled in a form with an email address field that required remote validation and pressed the form submit button immediately without leaving the focus of the email field.

    It appears that the default functionality of the validation is to validate when focus leaves the field. When you press the submit button focus does leave the field, but since the remote validation is done asynchronously, the form is incorrectly validated as correct and submitted at around the same time as the remote validation check.

    The async parameter should fix this, but I think in your case you might need to put the async: false as a parameter of the remote section, rather than the email rule. Try and replace your email rule with this instead:

    email: { required: true, email: true, minlength: 3, remote: { url: “checkemail.php, async: false } }

    If that still doesn’t work, you can do the remote validation yourself and still keep it asynchronous, you just need to provide a callback function in the remote validation check, which only submits the form if the remote validation passed:

    $("#subscribe_test3").submit(function(e){
      if ($(this).valid()){
        $.get("/check_subscribed.php",
          { email: $("#subscribe_test3_email").val() },
          function(data) {
            if (data){
              $.ajax( {
                type: "POST",
                url: "/save_subscriber.php",
                data: "email="+$("#subscribe_test3_email").val(),
                success: function(data){
                  $("#submit_result").html("Ajax submit results:" + data);
                }
              } );
            }
          },
          "json"
        );
      }
      return false;
    });

    I think the first fix should work for you, though. Let us know of the results!

  12. Thanks for greate tut!
    I’m trying use Jqurey validate for option remote following code below
    username:{
    remote: {
    url: SITE_URL + ‘/admin/user/checkUser’,
    type: ‘POST’,
    async: false,
    data: {
    username: function() {
    return $(“#username”).val();
    }
    }
    }
    }
    and this message
    messages: {
    username: { remote: “Already subscribed”}
    }
    but it doesn’t work. Please help me. I dont know how it doesnt work
    Sorry for my english.

  13. my function checkUser just echo “false”;
    But message for remote is not show. :(

  14. Ok, as far as I can tell that code looks ok, for it to work the following things need to be correct. You have a form with an input field with name ‘username’ which also has id of ‘username’. You have some script running at your site url which returns a string ‘true’ or ‘false’. I noticed you didn’t have a .php extension on that url, I assume there is some url rewriting going on.
    Can I ask is the form actually validating and the username showing up as invalid? Is it just the message you specified not showing up? Try adding some log statements, both in your javascript username function (use console.log() and check with firebug or chrome developer tools) and in your server side script to check that both are being called.
    Other than that I don’t think I can help without seeing the complete form html and the complete javascript validation code.
    By the way I have a code highlight plugin installed on this site. You can use it in comment posts, e.g.
    [code lang=”javascript”]
    $(document).ready(function(){
    console.log(“Document is ready”);
    });
    [/code]
    Becomes:

    $(document).ready(function(){
        console.log("Document is ready");
    });
  15. Thank for your support.
    This is my code detail.
    HTML:

     

    JS:

    $("#myform").validate({
                    rules: {                                          
                        username:{  
                            remote: {
                                url: SITE_URL + ‘/admin/user/checkUser’,
                                type: ‘POST’,
                                async: false,
                                data: {
                                    username: function() {
                                        return $("#username").val();
                                    }
                                }                                                                                            
                            }                        
                        }
                    },
                    messages: {
                        username: { remote: "Already subscribed"}
                    }                                                      
                });

    PHP:
    i just echo “true”. That’s all!

    function checkUser() {
            echo "true";
        }
  16. The problem appears to be the PHP file, which just has a function named checkUser. Before I assumed that your remote URL was being rewritten on the server to be directed to the correct PHP code, but if this is not the case then you need to refer directly to a PHP file itself and not a function inside the php file.
    So if the php file is called checkUser.php and located inside the /admin/user/ directory your remote validation url would be SITE_URL + ‘/admin/user/checkUser.php’

    Also inside the php file you can’t just have a function, but if you do it needs to be invoked. If that is all the php file contains the function is unnecessary, but for reference if you use a function you need to invoke it.

    function checkUser() {
        echo "true";
    }
    checkUser();

    Hope this helps.

  17. Thanks for supporting but it’s not work T_T
    I’m using CodeIgniter Framework (www.codeigniter.com) so when i call URL following SITE_URL + ‘admin/user/checkUser’ then function checkUser will automatically invoke
    Now, i have finished that project by using another way not jquery validate, i still try to find out Jquery validate integrate with CodeIgniter.
    By the way, your blog is so cool, i have learned many thing from this site. Thanks

  18. Ah I see, I’ve never used CodeIgniter before, that function invocation sounds like fun. I’m not sure what to suggest then apart from putting log statements on the server side and using a tool like firebug or chrome developer tools to see if the remote validation request is actually taking place. You can see in the network section the requests being made and you can check the response body only contains the text ‘true’.
    Thanks for the nice comments, I’m glad the site is useful, I wish I had more time to make more posts but am really busy with work. I’ll make an extra effort to post more regularly!

  19. Hi! I have a similar solution, and when the remote validation time out or aborts, the form gets unsubmitable. Validation is still on, but the remote validation doesnt get triggered when I change the field value or submits the form again.
    Anyone experienced this problem?

    -C

  20. I’ve never experienced a problem with remote validation timing out. That’s a server side issue, but it makes sense that the validation won’t get triggered if the async attribute is set to false, since it will wait for the server to respond. With async false the validation is basically blocked until the remote validation request gets a response. You will need to sort out the reason why the request is timing out or failing, these remote validation requests should really only take a second or two to run, anything longer I think is a usability issue.

  21. This is a great example, thanks