Wednesday, November 26, 2008

jQuery Validation Plugin

This is an extension to Mohammed Nour El-Din's blog post on the jQuery Validation Plug-in; however, for ASP.NET Forms. Why Forms? Well, ASP.NET MVC is still beta and I sure most of our employers are NOT willing to support a beta product in a production environment. Therefore, until MVC is production ready and supported by the enterprise, we must make accommodations (hacks/workarounds) to support non-out-of-box scenarios. Besides, jQuery is awesome, and get this, it is now supported and encouraged by Microsoft.

Just to sure, I assume that if you are reading this blog entry you are familiar with jQuery, the jQuery Plug-in, ASP.NET, and client-side programming with ASP.NET. If not, Google the respective topic.

All of my statement's here are from my experience using the jQuery Validation Plug-in with ASP.NET. I have tried many different ways to make the plugin work with ASP.NET; however, I find that the following implementation fulfills my requirements the best.

The jQuery Validation Plug-in (and jQuery in general) follows the method of Convention over Configuration. The plug-in extensively uses and input control's name attribute by conversion so the user does not have to configure the plug-in to work; therefore, it just works. The plug-in also assumes that a control's name and id attributes are the same. In the ASP.NET world, this is not the case out-of-the-box. Out-of-the-box, a control's name attribute replaces the underscore (_) character with a US currency sign ($). The strategic reasons as to why ASP.NET implements this convention are out of scope for this post; however, you can find must more on Microsoft.com or via Google.

For these examples, I am using jQuery 1.2.6, the Validation Plug-in, the jQuery Forms Plug-in and ASP.NET 3.5. The following are my external JavaScript references:

1 <script language="javascript" type="text/javascript" src="jquery-1.2.6.pack.js">script>

2 <script language="javascript" type="text/javascript" src="jquery-validate/jquery.validate.js">script>

3 <script language="javascript" type="text/javascript" src="jquery-validate/lib/jquery.form.js">script>

The following are my styles:

1 <style type="text/css">

2 div.field-container { margin: 5px; }

3 label.labelField { width: 100px; display: block; float: left; }

4 label.error { font: bold 11px Verdana; color: Red; font-style:italic; padding-left: 10px; display: block; }

5 input[type=text], input[type=password] { border: 1px solid #7b9ebd; }

6 input:focus { border: 1px dotted black; }

7 input.error { border: 1px dotted red; }

8 style>

The following is the markup for the ASP.NET controls:

1 <div class="field-container">

2 <label class="labelField">

3 <span>First Name:span>

4 label>

5 <asp:TextBox ID="txtFirstName" runat="server" />

6 div>

7

8 <div class="field-container">

9 <label class="labelField">

10 <span>Last Name:span>

11 label>

12 <asp:TextBox runat="server" ID="txtLastName" />

13 div>

14

15 <div class="field-container">

16 <label class="labelField">

17 <span>User Name:span>

18 label>

19 <asp:TextBox runat="server" ID="txtUserName" />

20 div>

21

22 <div class="field-container">

23 <label class="labelField">

24 <span>Email:span>

25 label>

26 <asp:TextBox runat="server" ID="txtEmail" />

27 div>

28

29 <div class="field-container">

30 <label class="labelField">

31 <span>Password:span>

32 label>

33 <asp:TextBox runat="server" ID="txtPassword" TextMode="Password" />

34 div>

35

36 <div class="field-container">

37 <label class="labelField">

38 <span>Web Site:span>

39 label>

40 <asp:TextBox runat="server" ID="txtWebsite" class="url" />

41 div>

Okay, now to the meat. The following is the JavaScript code that I use to create, add, and extend the Validate Plug-in:

1 <script language="javascript" type="text/javascript">

2 // object containing asp.net control ids

3 var _pageFields = {

4 form: '<%= Master.FormMaster.ClientID %>',

5 firstName: '<%= txtFirstName.ClientID %>',

6 lastName: '<%= txtLastName.ClientID %>',

7 userName: '<%= txtUserName.ClientID %>',

8 email: '<%= txtEmail.ClientID %>',

9 password: '<%= txtPassword.ClientID %>',

10 webSite: '<%= txtWebsite.ClientID %>'

11 };

12

13 $(document).ready(function() {

14 var addOption = function(selector, /* jQuery Selector */

15 isRule /* true: rule | false: message */,

16 optionObject, /* json-formmated object to pass to the validate jQuery extension */

17 optionsToAdd /* rule or message options object*/

18 ) {

19 var $element = $(selector);

20 if (!$element[0]) return;

21 var key = (!!isRule) ? 'rules' : 'messages';

22 optionObject[key][$element.attr('name')] = optionsToAdd;

23 };

24

25 // temp options object for use with validate jQuery extension

26 var options = { rules: {}, messages: {} };

27

28 // add first name options to options object

29 addOption('#' + _pageFields.firstName, true, options, {

30 required: true,

31 minlength: 2

32 });

33 addOption('#' + _pageFields.firstName, false, options, {

34 required: 'Please enter a First Name.',

35 minlength: 'Your First Name must consist of at least 2 characters.'

36 });

37

38 // add last name options to options object

39 addOption('#' + _pageFields.lastName, true, options, {

40 required: true,

41 minlength: 2

42 });

43 addOption('#' + _pageFields.lastName, false, options, {

44 required: 'Please enter a Last Name.',

45 minlength: 'Your Last Name must consist of at least 2 characters.'

46 });

47

48 // add user name options to options object

49 addOption('#' + _pageFields.userName, true, options, {

50 required: true, minlength: 2

51 });

52 addOption('#' + _pageFields.userName, false, options, {

53 required: 'Please enter a User Name.',

54 minlength: 'Your User Name must consist of at least 2 characters.'

55 });

56

57 // add email options to options object

58 addOption('#' + _pageFields.email, true, options, {

59 required: true,

60 minlength: 2

61 });

62 addOption('#' + _pageFields.email, false, options, {

63 required: 'Please enter an Email.',

64 minlength: 'Your Email must consist of at least 2 characters.'

65 });

66

67 // add password options to options object

68 addOption('#' + _pageFields.password, true, options, {

69 required: true,

70 minlength: 8

71 });

72 addOption('#' + _pageFields.password, false, options, {

73 required: 'Please enter a Password.',

74 minlength: 'Your Password must consist of at least 8 characters.'

75 });

76

77 // add website options to options object

78 addOption('#' + _pageFields.webSite, true, options, {

79 url: true

80 });

81

82 $('#' + _pageFields.form).validate(options);

83 });

84 script>

Okay, so all I am doing here is creating a client-side object that contains the ASP.NET generated client IDs for the HTML input controls (lines: 1 - 11). I know, it's ugly, but it's what I find to be the best implementation.

Then I use jQuery's 'When the DOM is ready, do this...' function - $(document).ready(function(){}); (starting line: 13).

Within the anonymous function passed to ready, I create a new function 'addOption' (line: 14), As you can see from the code, there are four function parameters. The parameters are self-documented; however, I have also include in-line comments. All that t function does is add a rule or message referencing the respective jQuery wrapped selector object as the rule or message object key. Again, I assume that you are familiar with the jQuery Validation Plug-in and the members/properties of the rules and messages option object. WHAT did he say? Check it out the home page: jQuery plugin: Validation and documentation: Plugins/Validation.

Okay, so I describe the process of using ASP.NET Forms controls with the jQuery Validation Plug-in using a very code-centric strategy. Sometimes you must experiment and experience the discomforts before you can actually get ASP.NET to cooperate with jQuery; however, don't let this discourage you. jQuery is here to stay and it is a very powerful JavaScript library.

BTW, I am using the awesome Visual Studio Plug-in CopySourceAsHtml (CSAH) to copy my source from Visual Studio to my HTML editior as HTML formatted markup. Check it out...

My intent was to write this blog entry so that I don't loose my finding somewhere on my hard drive. I hope these efforts help someone else out there. Thanks for reading...