Sunday, March 17, 2013

Custom Conditional Validation Depends on Another Property Value using JQuery Unobtrusive feature and ASP.NET MVC

 

Data Annotation Validation Attribute ( example [Required]) makes easy to provide validation in ASP.NET MVC. Also if Enable unobtrusive validation, we do not need to write any code in JavaScript for client validation. Jquery unobtrusive  validation parse the data attribute in HTML and we do not need to any custom code to validate form.

To enable client side  validation and unobtrusive validation we need to provide settings in web.config or in server side HtmlHelper.

 

   1: <appSettings>
   2:     <add key="ClientValidationEnabled" value="true" />
   3:     <add key="UnobtrusiveJavaScriptEnabled" value="true" />
   4: </appSettings>

or



   1: HtmlHelper.ClientValidationEnabled = true;
   2: HtmlHelper.UnobtrusiveJavaScriptEnabled = true;

If  jquery unobtrusive library is referenced in cshtml then there do not need to write any custom code to validate form with the help of data annotation validation attribute.



   1: public class CustomerFormModel : ICustomerCommand
   2:   {
   3:       public int Id { get; set; }
   4:       
   5:       [Required(AllowEmptyStrings = false, ErrorMessageResourceName = "CustomerNameRequired", ErrorMessageResourceType = typeof(StringTable))]
   6:       [StringLength(200, ErrorMessageResourceName = "CustomerNameLenthValidationError", ErrorMessageResourceType = typeof(StringTable))]
   7:       public string Name { get; set; }
   8: }

When this code will be executed the form can be validated automatically by jquery unobtrusive validation.


image


When you enable unobtrusive validation ASP.NET MVC add data attribute in HTML  for each data annotation.


image


In HTML attributes are generated for data annotation in server side and jquery unobtrusive library parsed those attribute for client validation.


But what will happen if validation on any field depends on the value of another field value. You may also want this validation not only client side but also in server side. Usually in such case we write custom validation before submitting form and also do same validation in server side.  We can also do same custom validation using Data annotation and jquery unobtrusive validation without directly referencing client control.


Suppose the requirement is to validate Email field as required only if Name field is not empty. So if Name field is not empty then we do not have to provide Email.


It this case the server side validation would be not difficult. We can create an data annotation attribute which will make decision based on value of Name property.


This is not final code.



   1: namespace SimpleTier.Domain.Validators
   2: {
   3:     using System;
   4:     using System.Collections.Generic;
   5:     using System.Linq;
   6:     using System.Text;
   7:     using System.ComponentModel.DataAnnotations;
   8:     using System.Web.Mvc;
   9:     using SimpleTier.Domain.Properties;
  10:  
  11:     public class EmailValueValidator : ValidationAttribute
  12:     {
  13:         private string _dependentPropery;
  14:         private bool _isRequired;
  15:         public EmailValueValidator(string dependentpropery, bool isrequired)
  16:             : base()
  17:         {
  18:             _dependentPropery = dependentpropery;
  19:             _isRequired = isrequired;
  20:         }
  21:  
  22:         protected override ValidationResult IsValid(object value, ValidationContext validationContext)
  23:         {
  24:             if (_isRequired == false) return null;
  25:             System.Reflection.PropertyInfo property = validationContext.ObjectType.GetProperty(_dependentPropery);
  26:             if (property != null)
  27:             {
  28:                 var value1 = property.GetValue(validationContext.ObjectInstance, null) as string;
  29:                 if (string.IsNullOrEmpty(value1) == false && string.IsNullOrEmpty(value as string))
  30:                     return new ValidationResult("Value can not be empty");
  31:  
  32:                 return null;
  33:  
  34:             }
  35:             else
  36:                 new ValidationResult(string.Format("Unknown Properties {0}", _dependentPropery));
  37:  
  38:             return null;
  39:  
  40:         }
  41:  
  42:     }
  43: }

In this code a custom validation attribute is created. IsValid() function gets the value of Name field and make decision based on Name value. Attribute on Email property can be defined as:



   1: public class CustomerFormModel : ICustomerCommand
   2:    {
   3:        public int Id { get; set; }
   4:        
   5:        [Required(AllowEmptyStrings = false, ErrorMessageResourceName = "CustomerNameRequired", ErrorMessageResourceType = typeof(StringTable))]
   6:        [StringLength(200, ErrorMessageResourceName = "CustomerNameLenthValidationError", ErrorMessageResourceType = typeof(StringTable))]
   7:        [TextLineInputValidator]
   8:        public string Name { get; set; }
   9:  
  10:        //[Required(AllowEmptyStrings = false, ErrorMessageResourceName = "EmailRequired", ErrorMessageResourceType = typeof(StringTable))]
  11:        [EmailValueValidator("Name",true)]
  12:        [StringLength(200, ErrorMessageResourceName = "EmailStringLengthValidationError", ErrorMessageResourceType = typeof(StringTable))]
  13:        public string Email { get; set; }
  14: }

Here Name is the property on which validation depends and also sets another value to determine validation logic is required or not.  But this validation works only on server side and in the HTML code no such validation attribute is created.


image


To make this validation work also on client side some Html attribute need to be created and make jquery unobtrusive library understand those attribute. To create those html attribute our custom attribute class need to be implemented  by IClientValidatable interface. If class is implemented by IClientValidatable interface,  method name GetClientValidationRules() can be implemented to define the rules that will be generate as html attribute.


 


image 



We need to define such rule in unobtrusive adapter so that client side validation understand these html attribute. unobtrusive adapter gives option to define method which will work with such rules and defined data attribute.



   1: <script type="text/javascript">
   2:     $.validator.unobtrusive.adapters.add(
   3:         'emailcustomvalidation',['dependentpropery','isrequired'],function(options)
   4:         {
   5:             options.rules["emailcustomvalidation"] =
   6:                 {
   7:                     dependentpropery: options.params.dependentpropery,
   8:                     isrequired: options.params.isrequired
   9:                 };
  10:             options.messages["emailcustomvalidation"] = options.message;
  11:         });
  12:     $.validator.addMethod("emailcustomvalidation", function(value, element, params)
  13:     {
  14:         var parts = element.name.split(".");
  15:         var prefix = "";
  16:         if (parts.length > 1)
  17:             prefix = parts[0] + ".";
  18:         var emailvalue = $('input[name="' + prefix + params.dependentpropery + '"]').val();
  19:         if (!value && !emailvalue)
  20:             return true;
  21:         if (emailvalue && !value)
  22:             return false;
  23:         return true;
  24:     })
  25:            
  26:     
  27: </script>

Here same validation is defined as server side code. When the save button will be clicked the form will be be validate and it will call this method. Client side validation provides same validation with error message defined in server side. Such validation can be used for multiple controls as that does not depend on any HTML control.

1 comment:

  1. vai Bangla name er kono validation code jana ace ki? pl give me that code.

    ReplyDelete