Search
Close this search box.

ASP.NET MVC Client-Side Validation Summary with jQuery Validation Plugin

UPDATE (2011-01-28):  ASP.NET MVC 3

I have a newer blog post that shows how to get Client Side Validation Summary without doing any of this.
I will still be answering questions and supporting this for developers who are still using ASP.NET MVC 2.

If you are on ASP.NET MVC 3, go here.

Problem

The MicrosoftMvcJQueryValidation.js script file, which integrates with the jQuery Validation Plugin, does NOT populate validation errors inside the Validation Summary control.
I will show you how to populate validation error messages into the Validation Summary control <%= Html.ValidationSummary(“Please fix the following errors.”) %>.

This code works 100% for both ASP.NET MVC 2 (Release Candidate 2) and ASP.NET MVC 2 RTM.
Sample Project download link at the bottom of the blog post.
 

Goal

We are going to tweak it to do the following.

  1. Inserts the client-side error messages into the Validation Summary <%= Html.ValidationSummary("Please fix the following errors.") %>  control.
  2. Show only asterisks for the  <%= Html.ValidationMessage("ColumnName")%> controls.
<script src="https://ajax.microsoft.com/ajax/jquery/jquery-1.4.2.min.js" type="text/javascript"></script>
<script src="https://ajax.microsoft.com/ajax/jQuery.Validate/1.6/jQuery.Validate.min.js" type="text/javascript"></script>
<script src="<%= Url.Content("~/scripts/MicrosoftMvcJQueryValidation.js") %>" type="text/javascript"></script> 

Yes, Microsoft CDN supports SSL, and that is why you are seeing https above.

Missing MicrosoftMvcJQueryValidation.js File

ASP.NET MVC 2 (Release Candidate 2) does NOT come with the MicrosoftMvcJQueryValidation.js script file like the ASP.NET MVC 2 (Beta) version.
So download the MVC RC2 source code from the CodePlex ASP.NET MVC section.
The MicrosoftMvcJQueryValidation.js script file is included in there somewhere.

Step 1: Create My Own Html Extension Method for Validation Summary

I need to use the following jQuery Validation Plugin’s options to insert client-side validation error messages into my Validation Summary DOM node.

  1. errorContainer      === hide and show this container when validating.
  2. errorLabelContainer === hide and show this container when validating.
  3. wrapper             === wrap error labels with the specified element. Useful in combination with errorLabelContainer to create a list of error messages.

Problem is that  <%= Html.ValidationSummary("Please fix the following errors.") %>  control does NOT render when there are no ModelState errors.
Only when there are ModelState errors, it renders out like this.

<div class="validation-summary-errors">
	<span>Please fix the following errors.</span>
	<ul>
		<li>Error Message</li>
	</ul>
</div>

Because of that behavior, it presents a  slight problem with how we are going to integrate with the jQuery Validation Plugin.
So, we are going to create an Extension Method for the HtmlHelper class to render the HTML code at all times.

public static MvcHtmlString ValidationSummaryJQuery(this HtmlHelper htmlHelper, string message, IDictionary<string, object> htmlAttributes)
{
	if (!htmlHelper.ViewData.ModelState.IsValid)
		return htmlHelper.ValidationSummary(message, htmlAttributes);


	StringBuilder sb = new StringBuilder(Environment.NewLine);

	var divBuilder = new TagBuilder("div");
	divBuilder.MergeAttributes<string, object>(htmlAttributes);
	divBuilder.AddCssClass(HtmlHelper.ValidationSummaryValidCssClassName); // intentionally add VALID css class

	if (!string.IsNullOrEmpty(message))
	{
		//--------------------------------------------------------------------------------
		// Build an EMPTY error summary message <span> tag
		//--------------------------------------------------------------------------------
		var spanBuilder = new TagBuilder("span");
		spanBuilder.SetInnerText(message);
		sb.Append(spanBuilder.ToString(TagRenderMode.Normal)).Append(Environment.NewLine);
	}

	divBuilder.InnerHtml = sb.ToString();
	return MvcHtmlString.Create(divBuilder.ToString(TagRenderMode.Normal));
}
 

Step 2: Changes to Your MVC Views

Replace all of your

<%= Html.ValidationSummary("Please fix the following errors.") %>
with
<%= Html.ValidationSummaryJQuery(
        "Please fix the following errors.",
        new Dictionary<string, object> { { "id", "valSumContainer" /* This is important. You can change the "id" attribute value, but don't remove it */ } }) %>

Replace all of your

<%= Html.ValidationMessageFor(m => m.ColumnName)%>  with  <%= Html.ValidationMessageFor(m => m.ColumnName, "*") %>.
<%= Html.ValidationMessage("ColumnName")%>          with  <%= Html.ValidationMessage("ColumnName", "*") %>.

The reason is that I want to display a little asterisk next to the User Input Fields, and actual error message inside the Validation Summary.

Make sure your HTML Form Declaration Looks like this

<% Html.EnableClientValidation(); // IMPORTANT: this line MUST be *before* Html.BeginForm() block %>
<% using (Html.BeginForm()) { %>

	<!-- IMPORTANT: ViewContext.FormContext.ValidationSummaryId MUST match the Validation Summary ID defined inside Html.ValidationSummaryJQuery() block */ -->
	<% ViewContext.FormContext.ValidationSummaryId = "valSumContainer"; %>

<% } >%

Use these CSS styles and you can tweak them if you’d like to.

/*----------------------------------------------------------
ASP.NET MVC FRAMEWORK DEFAULT CSS CLASS NAMES
----------------------------------------------------------*/
.error,.field-validation-error{color:red}

.input-validation-valid,.field-validation-valid,.validation-summary-valid{display:none}
.input-validation-error{background-color:#fee;border:1px solid red; outline: none}
.input-validation-error:focus{outline:none}
input[type="text"].input-validation-error:focus, select.input-validation-error:focus{outline:none}

.validation-summary-errors{color:red}
.validation-summary-errors span{font-weight:700}
.validation-summary-errors ul{list-style:disc inside}
.validation-summary-errors ul li{font-weight:normal}
.validation-summary-errors ul li label, .validation-summary-errors ul li span{display:inline !important; font-weight:normal}

Step 3: Custom Code for the MicrosoftMvcJQueryValidation.js File

Let’s add the following code into the MicrosoftMvcJQueryValidation.js script file.

var validationSummaryId = validationContext.ValidationSummaryId;
if (validationSummaryId) {
  // insert an empty <ul> into the validation summary <div> tag (as necessary)
  $("<ul />").appendTo($("#" + validationSummaryId + ":not(:has(ul:first))"));

  options = {errorContainer : "#" + validationSummaryId,
             errorLabelContainer : "#" + validationSummaryId + " ul:first",
             wrapper : "li",

             showErrors : function(errorMap, errorList){
                 var errContainer = $(this.settings.errorContainer);
  var errLabelContainer = $("ul:first", errContainer);

  // Add error CSS class to user-input controls with errors
  for (var i = 0; this.errorList[i]; i++) {
    var element = this.errorList[i].element;
    var messageSpan = $(fieldToMessageMappings[element.name]);
    var msgSpanHtml = messageSpan.html();
    if (!msgSpanHtml || msgSpanHtml.length == 0) {
      // Don't override the existing Validation Message.
      // Only if it is empty, set it to an asterisk.
      messageSpan.html("*");
    }
    messageSpan.removeClass("field-validation-valid")
        .addClass("field-validation-error");
    $("#" + element.id).addClass("input-validation-error");
  }
  for (var i = 0; this.successList[i]; i++) {
    // Remove error CSS class from user-input controls with zero validation
    // errors
    var element = this.successList[i];
    var messageSpan = fieldToMessageMappings[element.name];
    $(messageSpan)
        .addClass("field-validation-valid")
        .removeClass("field-validation-error");
    $("#" + element.id).removeClass("input-validation-error");
  }

  if (this.numberOfInvalids() > 0) {
    errContainer.removeClass("validation-summary-valid")
        .addClass("validation-summary-errors");
  }

  this.defaultShowErrors();

  // when server-side errors still exist in the Validation Summary, don't hide
  // it
  var totalErrorCount =
      errLabelContainer.children("li:not(:has(label))").length +
      this.numberOfInvalids();
  if (totalErrorCount > 0) {
    $(this.settings.errorContainer)
        .css("display", "block")
        .addClass("validation-summary-errors")
        .removeClass("validation-summary-valid");
    $(this.settings.errorLabelContainer).css("display", "block");
  }
}
, messages : errorMessagesObj, rules : rulesObj
}
;
}

A Few Important Things

  1. Properties like this.errorList and this.successList in my code above are NOT documented properties of the jQuery Validation Plugin.
    I used FireBug AddOn (everybody loves it, who doesn’t) in FireFox to step into the JavaScript debugging and inspected the properties available in the jQuery validation plugin “class”.

    Therefore, if the jQuery Validation Plugin author(s) change(s) any of these property names in the future, this code will NOT work.
    The jQuery Validation Plugin Version I am currently using is jQuery Validation Plugin (Version 1.6).

     
  2. I have tested my code works correctly on IE6-IE7-IE8, FireFox, and Google Chrome browsers.
    I don’t know if it works in Opera or other browsers. You’re on your own for that.

     

Step 4: Where to Add the Step #3 Custom Code in the MicrosoftMvcJQueryValidation.js File

We are not replacing any existing code in the MicrosoftMvcJQueryValidation.js script file.

We are only ADDING my custom code block near the bottom of it where it defines the JavaScript Variable (jQuery Validation Plugin Options)   var options = { ... }.
So add my code block right after the  var options = { ... }  original block.

The reason is that I want to keep the default client-side validation behavior, and only use my behavior if and only if the Validation Summary Container ID is specified.
That is why I said the "id" attr is important when I wrote this code.

<%= Html.ValidationSummaryJQuery(
        "Please fix the following errors.",
        new Dictionary<string, object> { { "id", "valSumContainer" /* This is important. You can change the "id" attribute value, but don't remove it */ } }) %>

I hope this is very useful to some people who are obsessive compulsive like me that wants to keep JavaScript Library <script> includes to a minimum.

Cheers,
Soe
 

Here is the sample project download link

This article is part of the GWB Archives. Original Author: Soe Tun

Related Posts