Wednesday, September 10, 2008

Starting With jQuery - Dynamically Applying Rules

This series of posts on using jQuery with no prior knowledge comes to its fourth iteration.  So far, we've went over how to use jQuery for simple UI design, some of the UI effects that jQuery has to offer, and an introduction to the Validation Plug-in.  Today, we're going to build on the Validation plug-in by looking at how to add and remove rules dynamically.

If you would like to review the previous posts in this series, please feel free to review the links below:

In order to use the Validation plug-in, you'll need to add a few things to your web page:

To make matters easier as well, all example code used in this post can be downloaded from here: Starting With jQuery - Dynamically Applying Rules.zip

 

Why Is This Important?

As I was learning jQuery, I wanted to know how to streamline my client-side validation for my ASP.Net applications.  There were two challenges that I came across with traditional ASP.Net Web Form applications;  ASP.Net Web Pages can only have 1 HTML form with runat="server", and ASP.Net Button Server controls render as submit buttons.  Through these two challenges, it became obvious that I couldn't set my validation rules as was described in the previous post since the Validation Plug-in validates the form onSubmit.  With multiple ASP.Net Button server controls and only 1 form to contain all of these buttons, I had to dive deeper into the Validation plug-in to discover how I could add and remove rules dynamically so that buttons that wouldn't require validation would still function correctly.

In addition to the Validation Plug-in documentation, I scoured the Internet for examples of what I was doing.  While I found a very large amount of people using jQuery's Validation Plug-in with the Microsoft ASP.Net MVC Framework, I struggled to find a standard ASP.Net Web Forms example.  Hopefully, this post will help fill that gap.

Even though my initial problem domain revolved around traditional ASP.Net web forms, I'm keeping these examples in plain HTML for simplicity. In the future, I am planning on exploring applying jQuery with ASP.Net components such as Master Pages and User Controls, so stay tuned.

 

The Examples

This week's example has 2 web pages associated with 2 different JavaScript files.  The reason for the 2 sets of files is to see the challenges described above (as portrayed through Default1.htm and ValidationRules1.js) as well as provide a "fixed" version (as portrayed in Default2.htm and ValidationRules2.js).

 

The Form

The HTML form used in the example is the same as the last post with 2 minor differences.  First, I've changed the colors after some colleagues made some comments about it (thanks guys!), and second, I added a second Submit button.  All in all the form is very simple.  The second example form adds additional elements as well and we'll cover them in a moment.

jQuery4-img1

 

Looking at the Old Way

By viewing Default1.htm in a web browser, clicking on the Submit #1 button will cause basic validation to occur, just like the previous post's example.  If you refresh the page and click on the Submit #2 button instead, we see the same behavior.

Opening up the Scripts/ValidationRules1.js file in your favorite text editor, you will see the same validation methodology used in the previous post. 

   1: //Our validation script will go here.
   2: $(document).ready(function(){
   3:  
   4:     //validation implementation will go here.
   5:     $("#TestForm").validate({
   6:         rules: {
   7:             txtFirstName: {
   8:                 required: true
   9:             },
  10:             txtLastName: {
  11:                 required: true,
  12:                 minlength: 2
  13:             }
  14:         },
  15:         messages: {
  16:             txtFirstName: {
  17:                 required: "* Required"
  18:             },
  19:             txtLastName: {
  20:                 required: "* Required",
  21:                 minlength: "* 2 Characters Required."
  22:             }
  23:         }
  24:     });
  25: })

This code attaches the validation rules to the specified form's controls and adds the validation method to the form's onSubmit event handler behind the scenes.  Since both Submit #1 and Submit #2 buttons are of type "submit", both buttons submit the form and trigger the validation code to fire.

If we wanted to change which fields are validated based on the button pressed, we need to modify the way we do things.

 

Apply and Removing Rules Dynamically

Open Default2.htm in a web browser to see that the form has changed slightly.  A new form field for the user to type in an email address has been added and the submit buttons have been relabeled.  Upon clicking on the "Validate Name" button, you'll see that First Name and Last Name are required fields.  By clicking on the "Validate Email" button, you see that the First Name and Last Name required labels disappear and a new label informing that Email is required appears.

jQuery4-img2

In order to accomplish these changes to the validation rules, new functions need to be written to dynamically add and remove the rules as necessary. 

   1: function validateEmailOnly(){
   2:     $("#txtEmail").rules("add", "required");
   3:     $("#txtFirstName").rules("remove", "required");
   4:     $("#txtLastName").rules("remove", "required minlength");
   5: }
   6:  
   7: function validateNameOnly(){
   8:     $("#txtFirstName").rules("add", "required");
   9:     $("#txtLastName").rules("add", {required:true, minlength:2});
  10:     $("#txtEmail").rules("remove", "required");
  11: }

The validateEmailOnly() function is called by the "Validate Email" button.  This function adds a required rule to the txtEmail form field and then removes the rules from txtFirstName and txtLastName fields.  The validateNameOnly() function works the same way but with the actions reversed.

 

Adding a Rule Dynamically

As you can see from the previous code block, adding a rule is fairly straight forward; however, there's 2 ways to do it.  The first way, as seen in the validateEmailOnly() function, applies only when you are adding a single, boolean (true/false) rule to a field.  In this scenario, we use the following syntax:

$("#txtEmail").rules("add", "required");

Dissecting this, we first get a jQuery object representation of the txtEmail form field.  Next, we call the rules() function, which in this instance accepts 2 parameters; an action and the name of the rule.  The action of "add" tells jQuery that we'll be adding this rule to the field for validation.  The rule parameter, in this case, accepts a boolean rule like required as a string value.

In the event that you want to add multiple rules to an element or just a single rule that is not boolean, like the minlength rule, then you can pass in an object as the rules parameter of the rules() function.  This way was demonstrated via the validateNameOnly() method through the following syntax:

$("#txtLastName").rules("add", {required:true, minlength:2});

 

Removing a Rule Dynamically

Now that we know how to add a rule dynamically, removing such is just as easy.  In order to remove a rule, we use the almost the same syntax as shown below:

$("#txtLastName").rules("remove", "required minlength");

There are only two things different when we remove instead of add rules.  The first is that the action changes to "remove" instead of "add".  The second difference is you specify the rules to remove in a space delimited string (as depicted above which removes both the "required" and the "minlength"  rules).

Prerequisites to Adding Rules

In order to apply rules to a field dynamically, the field has to be within a form that the jQuery Validation Plug-in will validate.  In the example code, this is handled already by building on the previous example.  Since we call the $("#TestForm").validate() function in document ready block of the script, all of the plumbing is handled for us.  If the validate() function isn't called on document ready, then the call will need to be made prior to applying your rules to ensure that the plug-in will act appropriately.

 

Limitations of Dynamically Adding Rules

With this flexibility, there is one limitation: there is no way to dynamically set a message.  There is no messages() function like there is a rules() function.  Because of this, a dynamically added rule will use its default message or the form field's title attribute value if present.  In order to overcome this issue is to call the form's validate() method (as described in the Prerequisites to Adding Rules section above) on document ready and setting the messages for all fields there.  Setting messages for rules does not apply those rules implicitly so you can set every field that will be validated in some way with every message if you wanted and still be fine.  This can be seen in the differences between the Email field's validation message and that of the Name fields.

 

Conclusion

That's it for this post.  I hope that you found it helpful in your jQuery Validation endeavors.  Next week we'll be diving into creating our own custom validation rules, and shortly there after I'm going to begin examining the challenges of using this great tool with traditional ASP.Net web forms.

Download This Weeks Code: Starting with jQuery - Dynamically Applying Rules.zip

kick it on DotNetKicks.com

5 comments:

  1. Great post. Just wanted to add that you can change the title attribute dynamically though prior to adding the rule using say $("#txt").attr("title", "new message"). Check out my post http://beckelman.net/post/2008/09/10/Client-Side-Validating-Bulk-Insert-With-jQuery-Validation-Plugin.aspx that does this. Thanks for sharing your great explanation.

    ReplyDelete
  2. You can just add a css class of "cancel" to the controls that you don't want to cause validation.

    ReplyDelete
  3. This is most helpful. I have a basic question that I just cannot seem to get a solution to. How do you add messages and rules when the clientID is differet from the id in the source. i.e. txtStartDate -> ct100_cphHead_txtStartDate?

    ReplyDelete
  4. Que tal, yo no sé escribir en ingles jejejej pero si leerlo y tu documento me ha ayudado mucho, muchas gracias.

    ReplyDelete
  5. Good article, but:
    Texts normally (already) are added.
    example:
    $("#inp_title").rules( 'add', { required: true, messages:{ required:"the title is empty, panic!" } } );

    (c) used Google Translate

    ReplyDelete