Showing posts with label Validation Summary. Show all posts
Showing posts with label Validation Summary. Show all posts

Creating a custom ASP.NET MVC @Html.ValidationSummary template styled with Bootstrap 3 panel

Today I had to customize the standard @Html.ValidationSummary that comes with ASP.NET MVC. Searched for it as always using Google and found this question at StackOverflow with two promising answers. One of them presented a nice approach that is the creation of a custom partial view called ValidationSummary.cshtml that lives in the standard Views\Shared folder. Initially I was afraid of implementing this because as one of the commenters said it didn’t play ball with jQuery Validate. I decided to experiment and see what would happen in my case. Guess what? It didn’t play ball with jQuery Validate. So it’s not OK. I was not satisfied and did further investigation regarding Microsoft's jquery.validate.unobtrusive.js file and it led me to the correct implementation to get the custom Validation Summary working with jQuery Validate. Let’s look at the code that Microsoft uses to fill the Validation Summary with errors:

function onErrors(event, validator) {  // 'this' is the form element
    var container = $(this).find("[data-valmsg-summary=true]"),
        list = container.find("ul");

    if (list && list.length && validator.errorList.length) {
        list.empty();
        container.addClass("validation-summary-errors").removeClass("validation-summary-valid");

        $.each(validator.errorList, function () {
            $("<li />").html(this.message).appendTo(list);
        });
    }
}

As we can see the code looks for a container that has a data attribute [data-valmsg-summary=true]. So when creating our custom Validation Summary template we must add that data attribute to our <div> container like this:

@model ModelStateDictionary

<div class='@(Html.ViewData.ModelState.IsValid ? "validation-summary-valid" : "validation-summary-errors") panel panel-danger'
     data-valmsg-summary="true">
    <div class="panel-heading">
        @Localization.CorrectErrors
    </div>
    <div class="panel-body">
        <ul>
            @foreach (var modelError in Model.SelectMany(keyValuePair => keyValuePair.Value.Errors))
            {
                <li>@modelError.ErrorMessage</li>
            }
        </ul>
    </div>
</div>

This Partial View approach gives you total control over what HTML structure/tags, CSS classes, etc you want applied to the validation summary.

Two things to take not in the above code:

1 - When the form is accessed for the 1st time, ModelState.IsValid is true and the CSS class validation-summary-valid is applied to the containing <div>.This is so so that it conforms to the standard ValidationSummary that comes with ASP.NET MVC and because this CSS class is used by jQuery unobtrusive validation code.
The standard Site.css file that comes with an empty ASP.NET MVC project also uses this very CSS class to hide the validation summary initially. It has this CSS rule:

.validation-summary-valid {
    display: none;
}

When post backing the form data, the view Model may pass the unobtrusive client side validation but may not pass the server side validation and in this case ModelState.IsValid will be false. Again to be conformant with jquery validate unobtrusive code we must set the class validation-summary-errors to the validation summary container. This is imperative; if we do not do this, then we won’t see the validation errors that come from the server side since the validation summary will be hidden.

2 - panel panel-danger are Bootstrap’s CSS classes that give some charming to our custom ValidationSummary. You can check Bootstrap 3 panel component here.

Following the above simple HTML structure it’s possible to make the custom validation summary compatible with jQuery Validate.

Here’s the end result:

ASP.NET MVC Custom Validation Summary with Bootrap 3 Look & Feel using Panel component

To get the above look & feel I changed some CSS classes in ~/Content/Site.css file to override Bootstrap’s CSS. Here are them:

.panel-body {
    padding: 10px;
}

ul, ol
{
    margin-bottom: 0;
    padding-left: 17px;
}

.panel
{
    margin-bottom: 0;
}

.form-group {
    margin-bottom: 0;
}

As a final take on this matter, it’d be great if the standard ASP.NET MVC @Html.ValidationSummary had a method overload accepting a template name. Let’s hope that in the future this gets added.

I assembled a sample ASP.NET MVC project and uploaded it to GitHub. Feel free to play with it and adapt it to your use case. Here’s it is: https://github.com/leniel/AspNetMvcCustomHtmlValidationSummary

Happy coding! Party smile