Custom Validation Message Helper in ASP.NET MVC

Introduction

I wrote an earlier post about Creating Custom Html Helpers in ASP.NET MVC which emphasized on how we can write custom html helper extensions in ASP.NET MVC according to our need, so that we can reuse them in our complete application, instead of writing plain html in View.

The example in that article was using ActionLink, today I am going to tell how we can implement custom Validation Message helper. I wanted to modify the validation message displaying in my application so that it displays * in front of required fields and the error message in tooltip of it like,

sign up
For that, add a class in the project and add an extension method which will render our custom html that will be displayed for error message,

  1. namespace CustomValidationMessageHelper.Helpers     
  2. {    
  3.     public static class Validator     
  4.     {    
  5.         public static MvcHtmlString MyValidationMessageFor < TModel,    
  6.             TProperty > (this HtmlHelper < TModel > helper,    
  7.                 Expression < Func < TModel, TProperty >> expression)    
  8.         {    
  9.                 TagBuilder containerDivBuilder = new TagBuilder("div");    
  10.                 containerDivBuilder.AddCssClass("tip_trigger");    
  11.                 containerDivBuilder.InnerHtml = "*";    
  12.     
  13.                 TagBuilder midDivBuilder = new TagBuilder("div");    
  14.                 midDivBuilder.AddCssClass("classic");    
  15.                 midDivBuilder.AddCssClass("tip");    
  16.                 midDivBuilder.InnerHtml = helper.ValidationMessageFor(expression).ToString();    
  17.     
  18.                 containerDivBuilder.InnerHtml += midDivBuilder.ToString(TagRenderMode.Normal);    
  19.     
  20.                 return MvcHtmlString.Create(containerDivBuilder.ToString(TagRenderMode.Normal));    
  21.             }    
  22.     }    
  23. }    

and then define the following CSS in a CSS file, in my case it is site.css or you can add it in the view,

  1. .validated     
  2. {    
  3.     border - color: #DCE4EC!important;    
  4. }    
  5.     
  6. textarea, input[type = "text"], input[type = "password"],    
  7.     input[type = "datetime"],    
  8.     input[type = "datetime-local"], input[type = "date"],    
  9.     input[type = "month"],    
  10.     input[type = "time"], input[type = "week"],    
  11.     input[type = "number"], input[type = "email"],    
  12.     input[type = "url"], input[type = "search"],    
  13.     input[type = "tel"], input[type = "color"],    
  14.     .uneditable - input {    
  15.         padding: 3 px 3 px;    
  16.         border: 1 px solid# DCE4EC;    
  17.     }    
  18.     
  19. .tip     
  20. {    
  21.     background: none repeat scroll 0 0# FFFFFF;    
  22.     border: 1 px solid #808080;    
  23. border-radius: 10px;    
  24. box-shadow: 0 1px 10px rgba(32, 32, 32, 0.5);    
  25. color: red;    
  26. display: none;    
  27. font-size: 12px;    
  28. font-style: normal;    
  29. margin-left: 10px;    
  30. margin-top: -24px;    
  31. padding: 4px;    
  32. position: absolute;    
  33. z-index: 999999;    
  34. }    
  35.     
  36. .tip_trigger     
  37. {    
  38. width: 10px;    
  39. float: right;    
  40. color: red;    
  41. margin-left: 3px;    
  42. }    
Now we have to add client side code, which I have written in jQuery in a js file or directly in view. In my case, I have it in CustomValidation.js file,
  1. $(document).ready(function()    
  2.   {    
  3.     //Tooltips    
  4.     var tip;    
  5.     $(".tip_trigger").hover(function()     
  6.         {    
  7.         console.log("hovered");    
  8.         tip = $(this).find('.tip');    
  9.         console.log($(this).find('.tip').find('span').html())    
  10.         if ($(this).find('.tip').find('span').html() != '')    
  11.         {    
  12.             $(this).find('.tip').show(); //Show tooltip    
  13.         }    
  14.     }, function()     
  15.      {    
  16.         $(this).find('.tip').hide(); //Hide tooltip     
  17.     });    
  18.     
  19.     ////Required fields    
  20.     $('input').each(function()    
  21.         {    
  22.         var req = $(this).attr('data-val-required');    
  23.         if (undefined != req) {    
  24.             $(this).css("border-color""#DA9BA2")    
  25.     
  26.         }    
  27.         if ($(this).val() != '')     
  28.         {    
  29.     
  30.             $(this).addClass("validated");    
  31.         }    
  32.     });    
  33.     
  34.     $('input').blur(function()    
  35.         {    
  36.     
  37.         if ($(this).val() != '')     
  38.         {    
  39.     
  40.             $(this).addClass("validated");    
  41.         } else {    
  42.     
  43.             $(this).css("border-color""#DA9BA2")    
  44.         }    
  45.     });    
  46. });   
Now in the View, add the reference to the related js and css files in the head section of View:
  1. <link href="@Url.Content(" ~/Content/site.css ")" rel="stylesheet" />    
  2. <script src="@Url.Content(" ~/Scripts/jquery-1.9.1.js ")"></script>    
  3. <script src="@Url.Content(" ~/Scripts/jquery.unobtrusive-ajax.js ")"></script>    
  4. <script src="@Url.Content(" ~/Scripts/jquery.validate.js ")" type="text/javascript"></script>    
  5. <script src="@Url.Content(" ~/Scripts/jquery.validate.unobtrusive.js ")" type="text/javascript">    
  6. </script>    
  7. <script src="@Url.Content(" ~/Scripts/CustomValidation.js ")" type="text/javascript"></script>   
Now in your view, add using statement of the namespace and now you can access the Helper method in the View,
  1. @model CustomValidationMessageHelper.ViewModels.SignUpViewModel    
  2. @using CustomValidationMessageHelper.Helpers    
  3. @ {    
  4.     Layout = null;    
  5. }    
  6.     
  7. @Html.TextBoxFor(model => model.FirstName, new    
  8. {    
  9.     @class = "form-control input-sm"    
  10. })    
  11. @Html.MyValidationMessageFor(model => model.FirstName)    
The sample project can be downloaded from here.