How to use Bootstrap 3 validation states with ASP.NET MVC Forms

15 Feb 2015

Recently, when writing code for my blog post on drop downs, “DropDownListFor with Dictionaries in ASP.NET MVC and why SelectList wants to kill you”, I stumbled over an interesting problem – when using ASP.NET MVC HTML helpers, such as @Html.TextBoxFor() and @Html.DropDownListFor() to render controls and @Html.ValidationMessageFor() to render validation error messages, I realised that ASP.NET MVC uses its own CSS classes, so no errors are getting highlighted when using Bootstrap 3.

There’s nothing wrong with MVC as such in here, as it is meant to be CSS framework agnostic, meaning you should be able to use it with any CSS framework.

Problem

To get a better understanding of the problem, have a look at this HTML that’s generated by MVC on postback. It contains an error message for a required text field.

<div class="form-group">

    <label for="FirstName">First name</label>

    <input class="input-validation-error form-control" data-val="true"
           data-val-required="The First name field is required."
           id="FirstName" name="FirstName" type="text" value="">

    <span class="field-validation-error" data-valmsg-for="FirstName"
          data-valmsg-replace="true">The First name field is required.</span>
</div>

As you can see, ASP.NET uses its own CSS classes, such as input-validation-error (used to highlight control with an invalid value) and field-validation-error which contains explanatory text for the error.

Without proper styling the above HTML looks like this:

No styling on the control

Not too bad, but could be better. Bootstrap 3 has this awesome indication for invalid form controls, and it highlights the entire control and the error text:

Like a boss

So following Bootstrap’s own documentation we need to make sure that control with error has a parent with the class of has-error and the validation error message element needs to have the class of text-danger. That’s how HTML needs to look like to get proper error highlighting:

<div class="has-error form-group"> <!-- 'has-error' class has been added on parent form-group div -->

    <label for="FirstName">First name</label>

    <input class="input-validation-error form-control" data-val="true"
           data-val-required="The First name field is required."
           id="FirstName" name="FirstName" type="text" value="">

    <!-- 'text-danger' has been added on the span with validation error message -->
    <span class="text-danger field-validation-error" data-valmsg-for="FirstName"
          data-valmsg-replace="true">The First name field is required.</span>
</div>

Solution

It is clear that we just need to add two puny CSS classes, but how exactly this is done depends on whether you use client-side JavaScript validation or not.

No client-side validation

If your form is submitted to the server with no prior on-the-client JavaScript validation (old school! but it works), then you’ve got yourself the easiest of all fixed. You can just add these CSS classes whenever the page loads in the following fashion:

$(document).ready(function() {
    $('.input-validation-error').parents('.form-group').addClass('has-error');
    $('.field-validation-error').addClass('text-danger');
});

ASP.NET MVC Unobtrusive validation

Most likely though you’re using in-built ASP.NET MVC’s own unobtrusive jQuery validation, in which case we need to hook into success and errorPlacement events of the jQuery Validation Plugin:

$(document).ready(function () {
    var form = $('#userForm')
        , formData = $.data(form[0])
        , settings = formData.validator.settings
        // Store existing event handlers in local variables
        , oldErrorPlacement = settings.errorPlacement
        , oldSuccess = settings.success;

    settings.errorPlacement = function(label, element) {

        // Call old handler so it can update the HTML
        oldErrorPlacement(label, element);

        // Add Bootstrap classes to newly added elements
        label.parents('.form-group').addClass('has-error');
        label.addClass('text-danger');
    };

    settings.success = function(label) {
        // Remove error class from <div class="form-group">, but don't worry about
        // validation error messages as the plugin is going to remove it anyway
        label.parents('.form-group').removeClass('has-error');

        // Call old handler to do rest of the work
        oldSuccess(label);
    };
});

Now admittedly this is a tad hacky, I personally don’t like how our validation code assumes a number of dangerous things, such as knowledge of parameter lists for internal functions, but it works.

Fluent Validation

FluentValidation is another popular library for ASP.NET MVC, and given it integrates with standard validation, you can use solutions listed above to make it work.

DID IT HELP? GET SOME MORE!

You can get the source code for the examples used in this article here as a Zip archive or browse the code on GitHub.

Subscribe to my mailing list to get handy tips on working with the framework, various libraries and all sort of surrounding stuff. I never spam, period.


comments powered by Disqus