jQuery Validation Groups for ASP.Net Webforms

I recently published a plug-in via Nuget that makes using jQuery Validation with ASP.Net WebForms a little more elegant. There is a limitation when using jQuery Validation with WebForms where if you have two logical 'form' groups in an ASP.Net WebForm when you click 'submit' in one section the entire page will be validated.

Consider the below example. There are two sections, one to login and the other to sign up. I want the validation to only fire for the "First Name" field when the "Sign Up" button is clicked.

If I click on the "sign up" button, this happens:

Screen Shot 2012 08 25 at 16 25 38 Clicking on the "sign up" button also triggers the validation for the login section.

Why not use the standard ASP.Net Validation Controls?

The standard ASP.Net validation controls e.g. required field validator get around this problem with the concept of validation groups. The downside to using the standard ASP.Net controls is that you have to add the obtrusive markup into your page e.g:

<p>
 <asp:Label ID="uiFirstName" runat="server" AssociatedControlID="uxFirstName" Text="First name:"></asp:Label>
 <asp:TextBox ID="uxFirstName" runat="server" CssClass="required"></asp:TextBox>
 <asp:RequiredFieldValidator runat="server" ID="valFirstName" ControlToValidate="uxFirstName"></asp:RequiredFieldValidator>
</p>

Using jQuery Validation allows you to attach validation bindings either via JavaScript or using CSS class names, leaving a cleaner separation of concerns in the HTML markup. This is one of the main reasons as to why this plugin has become so popular.

Dave Ward wrote a great blog post addressing this problem where he offers a solution that will give us "validation groups" using jQuery Validation. This solution is great, but it leaves a side effect of having to write more JavaScript where there are multiple form sections on a page. I wanted the best of both worlds and something that could be used right out of the box for WebForm developers - which is what this plug-in aims to achieve.

How to use

If you are unfamiliar with jQuery Validation, please take a look at the documentation. This plug-in sits on top of jQuery Validation so all the features work as standard.

To set up jQuery Validation you have to attach the validate event to the form, as below:

        $(function() {
            $("#aspForm").validate();
        });

To make use of the jQuery Validation with ASP.Net WebForms plugin simply download the package via Nuget or get the JavaScript source file from Github (links are below) and change the event binding to the below:

        $(function() {
            $("#aspForm").validateWebForm();
        });

If we have multiple validation groups on a form, we can set this up using CSS names. Simply wrap an element around your validation section and give it a class name of "form". Next, on the submit action that should trigger the validation event just add the CSS class name "submit". That's it! Here is a basic example:

<fieldset class="form">

....

     <asp:Button ID="uxRegister" runat="server" Text="Sign Up" CssClass="submit" />

</fieldset>

Code Example

Here is a working example from the screen shot that uses the plug-in.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
 <title>Multiple Form Validation</title>
 <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
 <script type="text/javascript" src="http://ajax.aspnetcdn.com/ajax/jquery.validate/1.9/jquery.validate.min.js"></script>
 <script type="text/javascript" src="jquery.validation.net.webforms.min.js"></script>
 <script type="text/javascript">
 $(function() {
 $("#aspForm").validateWebForm();
 });
 </script>
 <style type="text/css">
 .error {
 color: red;
 }
 </style>
</head>
<body>
 <form id="aspForm" runat="server">
 <fieldset class="form" id="signup">
 <div class="something">
 <ul></ul>
 </div>
 <legend>Sign Up</legend>
 <p>
 <asp:Label ID="uiFirstName" runat="server" AssociatedControlID="uxFirstName" Text="First name:"></asp:Label>
 <asp:TextBox ID="uxFirstName" runat="server" CssClass="required"></asp:TextBox>
 </p>
 <p>
 <asp:Button ID="uxRegister" runat="server" Text="Sign Up" CssClass="submit signup" />
 <asp:Button ID="uxCancelRegister" runat="server" Text="Cancel" />
 </p>
 </fieldset>
 <fieldset class="form" id="login">
 <legend>Login</legend>
 <p>
 <asp:Label ID="uiUserName" runat="server" AssociatedControlID="uxUserName" Text="User name:"></asp:Label>
 <asp:TextBox ID="uxUserName" runat="server" CssClass="required email"></asp:TextBox>
 </p>
 <p>
 <asp:Button ID="uxLogin" runat="server" Text="Login" CssClass="submit login" />
 <asp:Button ID="uxCancelSignUp" runat="server" Text="Cancel" />
 </p>
 </fieldset>
 </form>
</body>
</html>

Download from Nuget

PM> Install-Package jQuery.Validation.WebForms

See the Nuget project page.

Source code on Github

You can download the full source here.

Future Changes

I have another enhancement in the pipeline, which will be to have different display settings for each validation section. Currently there is still the restriction to a single form element i.e. one set of display options per form.

If you have any feature requests or run into any issues with this plug-in please leave a comment.

40 comments:

  1. Great plugin. One issue I'm encountering. Let's say you have 3 forms on the page. You fill out the 2nd one (according to the order in the html markup), after you fill out all (or some) the fields, instead of clicking the actual submit button you press enter on the keyboard while still in focus in one of your form's input fields. What happens it the form above the second one gets validated too and all the error messages for that first form show up. Any forms below the ones input field focus don't trigger. Any way to get around this problem?

    ReplyDelete
    Replies
    1. Are the containing divs that represent the 'form' nested!

      Delete
    2. No, one form I have is a global site search and it's located at the top of the page in the header section. The other form is a registration form located down in the main content area of the page. Basically once I'm going through the registration form and click the return key on the keyboard while focused on one of the input fields within the second form, the site search form error triggers an error that that field is empty.

      Same issue if I have 2 sibling forms and I try to submit the 2nd form via a return key press.

      Delete
    3. Understood. I will try and update the source in the next 24 hours.

      Delete
    4. Hi, this should be corrected now. Either fetch a new version from the Github repository or try the update Nuget package. Thanks

      Delete
    5. Thanks Brad, this works great!

      Delete
  2. Hello Brad, I think I found another issue. Same deal as before with multiple forms on the page but this time it only happens when you're focused on an input with a type="password". If you try to submit the form via keydown enter from that input, any form above will get triggered for validation. Would you mind checking this out? The password field is usually the last item on a form as well so this might be more of an issue than what it sounds like.

    ReplyDelete
    Replies
    1. Good catch, that was a silly bug! It would have only worked with text fields. I've updated Github and Nuget. Thanks again for taking the time to let me know there was an issue!

      Delete
  3. Loving this cheers Brad, I've been wanting something to do this for a while now!

    ReplyDelete
  4. Hi Brad, this is just the thing I needed for my old asp.net webforms. I am having trouble using the submitHandler option. it seems to ignore it. When change back to validate() it works. Any ideas? Cheers.

    ReplyDelete
  5. This is great cheers Brad. Just one thing I am wondering. Why have you forced the onsubmit to to be false? Doing this removes the submitHandler function. which I need for my ajax submission. If I take this out, I can always set it in the options anyway.

    ReplyDelete
    Replies
    1. That's there to stop the validate event treating all the controls on the page as an entire form (which technically it is) which is not what we want otherwise we are back to the problem described in the first screen shot of this post! What are you using for AJAX i.e. standard .Net AJAX controls?

      Delete
    2. Example: I have an email signup form. The client side checks if I have filled out the relevant fields and checked if it is a valid email. Once that is valid, I then fire off my ajax request to check if the user has already signed up. this then returns the results, if success I can then post the form, else show my error message.

      Delete
    3. Understood, I'll take a look but it might take me a few days to get to this. In the meantime, you could experiment with something along the lines of:

      $("form").validate().submitHandler(); <-- maybe this will invoke the function you setup on the document.ready??

      In the source, you could add something here:

      isValid == // result from submitHandler response

      /* then the existing code should jump in */

      if (!isValid) {
      event.preventDefault();
      }

      Let me know how it goes, thanks for taking the timeout to mention this.

      Delete
    4. Thanks for this plugin Brad! I have the same issue. I want to use the submitHandler to submit my form via Ajax. I don't understand your solution above. Would you have an exemple?

      I was also trying to do something else. When I click on my submit button I want to check if the related form is valid. How would I do that?
      When I do it the usual way I get the same result as if I was not using your plugin.

      Thanks for you help!

      Delete
    5. Hi Anon,

      I'm taking a look at the submit handler problem now.

      As for your second question, if you click on a button and you want to know if that "validation group" is valid, simply add something like this:

      val groupIsValid = validateAndSubmit("#my-button-id");

      That method will find the parent div (with "form" class attribute) to which the submit button belongs and validate all the controls inside.

      Keep in mind that the controls you want to validate as a logical need to be in their own container with the class name "form" as an attribute e.g.

      <div class="form">


      &;tl/div>

      Hope this helps!

      Delete
    6. The HTML parser messed up my example - it was supposed to be a DIV container with the class FORM with the submit button inside.

      Delete
  6. OK thanks, that response got me thinking & I have reached a solution. A bit hacky and not great but it works. It just means I will have to add a lot of event listeners.

    I have added an else condition in your !isValid statement.

    if (!isValid) {
    event.preventDefault();
    }else{
    group.trigger('group-valid');
    }

    then in my code before I initiate the validate on the form if add a listener

    //custom event listener when group is valid
    $j('.newsletter-signup .form').bind('group-valid', $j.proxy(this, 'postData'));

    // validate webform
    this.$globalForm.validateWebForm();

    postData: function(){
    //ajax form post
    }

    If you do manage to get it worked into your plugin then It would be great to see your implementation. meanwhile I will use this method.

    Cheers
    Andrew

    ReplyDelete
    Replies
    1. Hi Andrew, a little later than I said but I finally got around to taking a look at this. Thanks for your code example.

      I've made a start on what I think will work, does this solve your problem?https://github.com/bbraithwaite/JQueryValidationForWebForms/blob/master/SubmitHandlerExample.aspx

      This just ensures that the submitHandler function is invoked (if it has been setup).

      NB I've yet to publish an update Nuget package for this, I will soon, but for now you can grab the latest code from the Github Repo.

      Delete
    2. Yes thanks, works a treat. Funny, I just left my desk to think about it a bit more and realised I could call the original function there. Turns out that's what you had done. Must have been staring at it too long. Cheers for the fast reply.

      Delete
  7. How can I put validation for minlength/maxlength and Compare?

    ReplyDelete
    Replies
    1. The same as you would using standard JQuery validation features e.g. http://jqueryvalidation.org/minlength-method/

      Delete
  8. Will this work for dropdown lists, multiselect boxes, etc?
    I've tried to add validation to a dropdownlist box and can't seem to get this to work.

    Code sample would be appreciated.

    ReplyDelete
    Replies
    1. See the second example from the following link:

      http://jqueryvalidation.org/required-method

      Delete
  9. Hi Brad!

    Thanks for the nice plugin!

    I have been giving it a try in my current project. While using it, I have discovered a few things which may be interesting for you:

    1) In the plugin's code we have the following:
    "
    // Select any input[type=text] elements within a validation group
    // and attach keydown handlers to all of them.
    $('.form :input').keydown(function (event)
    "
    I guess the comment is incorrect because ":input selector basically selects all form controls." (http://api.jquery.com/input-selector/). Therefore, the above-mentioned code adds click handler for all the form's controls (including selects and text areas). I am not sure about textarea - haven't checked, but it leads to submitting the form every time a user chooses some option in select by pressing enter key. You can reproduce it by clicking on a select and choosing an option using arrow keys and enter key. The described behaviour actually does not correlate with default form behaviour. Is it "by design"? If not then do you think it makes sense to change the selector, i.e. use $('.form input, .form button') instead of $('.form :input') ?

    2) Another problem is that I have an error when calling $('#mainForm').validateWebForm(...).element('someSelector') in order to validate a particular element. As far as I understand, webforms plugin sits on top of the original plugin, so there should be such a possibility. Can you please suggest on how to do it?

    Best Regards,
    Dmitry

    ReplyDelete
    Replies
    1. 1. Yes the comment is wrong (it should say "form"), as you correctly say it's the entire form. It seems you've spotted an edge case with this. The error key is handled for all elements, since the enter key will submit the entire form when pressed thus causing the very problem for which this plug-in exists i.e. it will submit the entire form.

      I guess there needs to be an IF statement within the keydown event to handle select elements i.e. IF the enter key is pressed within a select, just return true (default). I will take a look at this, but not within the next few days. Fancy putting together a pull request? :)

      2. It doesn't offer that. At line 50 the code is "return undefined" which is why you see the error. I have no plans to add this. As a suggestion, you could take some of the code in the validateAndSubmit method since this contains all the moving parts to be able to validate a single item.

      From the top of my head (un-tested):

      var isValid = $('someSelector').valid();

      Will this do what you need? You could modify the plugin to return:

      return wrapper; // as opposed to undefined

      'wrapper' will look something like this:

      wrapper: function () {
      element: function(selector) {
      return $(selector).valid();
      }
      }

      Please note this is from the top of my head and not tested, but it may help!

      Delete
  10. Hi Brad!

    1) Yes, it seems to be an edge case. I've changed selector to $('.form input, .form button') and feel happy with this solution, so I am not asking you to change the implementation :)

    2) Thanks for suggestion. I have changed validateWebForm() a little bit in order to be able to call element() method. I return this.validate(options) after all the processing is done. Haven't seen any drawbacks with this yet. What do you think, does it make sense?

    P.S. No rush in answering my questions.

    Regards,
    Dmitry

    ReplyDelete
    Replies
    1. 1) Be sure to check what happens when the enter key is pressed and a form is in an invalid state. Won't it bypass the validation e.g tab through some input elements and hit the enter key to submit the form (with elements in an invalid state)?

      2) Sounds like a good approach. I will test it out and if ok will update the source.

      Delete
  11. 1) I have a very simple form: 4 mandatory select + 1 non-mandatory checkbox. I've tried it out in the latest FF, Opera, Safari, Chrome, IE 7-9 and it certainly *does* validation - nothing is bypassed. I have also discovered that by default enter key does not submit the form when the focus is on a select in all the above-mentioned browsers except of Opera. So, I guess it should work fine in my case (with selects). Not sure about textarea though.

    2) OK

    ReplyDelete
  12. I want to create a wizard like this, using your validation plugin, not sure how this can be achieved?

    ReplyDelete
    Replies
    1. An option would be to make use of a submit handler to catch the submit event for each form of the wizard. See the example here:

      https://github.com/bbraithwaite/JQueryValidationForWebForms/blob/master/SubmitHandlerExample.aspx

      Delete
  13. Hi,

    Excellent project - solves the typical .net single-form problem nicely. I have a couple suggestions that solved my particular issues, but seem general-purpose. Let me know if you agree - I can do a pull request if you like (I haven't geared up on Git, but this could be an excuse to learn it).

    1. Handle nested forms. The keydown() call is all that's needed, and it can handle nested forms. (I only tested well-behaved nesting, not if form/submit classes are missing, overlapping, etc.).
    Details: It works nicely even with
    form(1)
    --form(2)
    --submit(2)
    --form(3)
    --submit(3)
    submit(1).

    Forms 2 and 3 individually authenticate and submit, and Form 1 includes all of them. This doesn't omit forms 2 and 3 from form 1 validation - by then, you might as well get them un-nested. It can also go deeper.

    2. Handle preventDefault. I needed to prevent validation and submission on the enter key, so did the typical keyCode 13 check, and event.preventDefault(). However, the keydown call fires the click. Adding a check for event.isDefaultPrevented lets this honor a previous prevent.

    These are both in the keydown section:
    // Select all input elements in form
    // and attach keydown handlers to all of them.
    $('.form :input').keydown(function (event) {
    // Cause the form to validate when the enter key is pressed, unless previously prevented.
    // It is a requirement to catch the enter key press as the default
    // browser action would submit the form bypassing the validation event thus validating all groups.
    // Find corresponding submit button to this input element, avoiding nested form/submit sections.
    if ((event.keyCode == 13) && !event.isDefaultPrevented) {
    var origForm = $(event.currentTarget).closest(".form");
    var submitButton = origForm.find(".submit").filter(function () {
    return origForm[0] == $(this).closest(".form")[0];
    });
    submitButton.click();

    return false;
    }
    });


    Thanks for the work!
    Bob Cooley
    (Blogger kept whacking my post trying to log in, so I just posted anonymously.)

    ReplyDelete
    Replies
    1. Hi Bob,

      Thanks for taking the time to share this. Be my guest if you would like to submit a pull request :)

      Delete
    2. Sure. I have a deadline (using this), then I'll come back soon to submit it.

      Delete
  14. Is there a way to add submit group validation to non-standard ASP.NET controls?
    I'm using an Infragistics WebImageButton control.
    I tried programmatically add attributes of CSS class, for e.g. .CssClass = "submit myGroup"
    I viewed source and found out that no matter what I tried with code-behind, it doesn't put the css class into HTML input element.

    The WebImageButton control has spans and divs wrapping the control.

    I was wondering if I could add the submit behaviour via javascript or not.

    Say for instance:

    ....
    rules: {
    '<%=WebImageButton1.ClientID%>': {
    submit = true,
    group = "myGroup"
    }
    },
    ...

    ReplyDelete
  15. Hi,

    We've been using your great extension for a while but have come across a problem. We have wired up the unhighlight event, but the element that is being passed into the function is the button that was clicked, not the element that is being validated - have you seen this before?

    Thnaks
    Al

    ReplyDelete
    Replies
    1. Hi,

      This plug-in doesn't cover every feature of JQuery validate.

      You could make a change to the source file. See (untested) code extract below from the jquery.validation.net.webforms.js file:


      group.find(':input').each(function (i, item) {
      if (!$(item).valid()) {

      if (settings.focusInvalid && isValid)
      $(item).focus();

      // ADD SOMETHING HERE?
      // Something like $(item).unhighlight()

      if (settings.invalidHandler)
      settings.invalidHandler(event, item);

      isValid = false;
      }
      });

      Delete
  16. Hi,i am using your great invention but i have problem on setting a range validation on textbox.i tried it using "rangelength" but it's not working or i am using it wrongly

    ReplyDelete
  17. Hello there, thanks in the first place.

    I want to make a question. I have a scenario where I need a 'form' in the master page (few fields only) and have the others in the aspx pages. When I try to use the method (validateaspnetwebforms) on the master and in the aspx, it doesn't work. Is that correct ? I just want to make sure about it, that I'm not doing anything wronng

    Thanks in advance, Rafael. Cheers from Brazil

    ReplyDelete
  18. How do you submit just the data within a group and not the entire form via a submit handler? I've tried wiring a function to a button, but I can see no way of validating the group and thus the wired function always fires. This does nothing:

    $("#save_button").click(function () {
    var groupIsValid = validateAndSubmit("#form_name");
    if (groupIsValid)...

    ReplyDelete