MVC Twitter Bootstrap unobtrusive error handling

Adam picture Adam · Apr 18, 2012 · Viewed 15k times · Source

I've been trying to get MVC Jquery unobtrusive error handling working with twitter bootstrap for some time now. Its got to the point were i'm either going to edit jquery.validate or do some hack and slash on document.ready.

In order to get unobtrusive error handling to work with Bootstrap and MVC I need to make it so the 'error' class it appended to the 'control-group' class. As well as that, the 'error' class is appended to the input.

I was wondering if anyone in the community has already found a solution.

For example

Typical bootstrap markup would be like so...

<div class="control-group">
    <label for="Username">Username</label>
    <div class="controls">
        <input data-val="true" data-val-required="Username is required" id="Username" name="Username" type="text" value="" />
        <span class="field-validation-valid" data-valmsg-for="Username" data-valmsg-replace="true"></span>
    </div>
</div>

What should happen, on blur when jquery.validate unobtrusive fires... it would change to the following

<div class="control-group error">
    <label for="Username">Username</label>
    <div class="controls">
        <input data-val="true" data-val-required="Username is required" id="Username" name="Username" type="text" value="" />
        <span class="field-validation-valid help-inline" data-valmsg-for="Username" data-valmsg-replace="true"></span>
    </div>
</div>

To get this to work on postback/submit you can do the following...

//twitter bootstrap on post
$(function () {
    $('span.field-validation-valid, span.field-validation-error').each(function () {
        $(this).addClass('help-inline');
    });

    $('form').submit(function () {
        if ($(this).valid()) {
            $(this).find('div.control-group').each(function () {
                if ($(this).find('span.field-validation-error').length == 0) {
                    $(this).removeClass('error');
                }
            });
        }
        else {
            $(this).find('div.control-group').each(function () {
                if ($(this).find('span.field-validation-error').length > 0) {
                    $(this).addClass('error');
                }
            });
        }
    });


    $('form').each(function () {
        $(this).find('div.control-group').each(function () {
            if ($(this).find('span.field-validation-error').length > 0) {
                $(this).addClass('error');
            }
        });
    });

});

However, on blur it won't work as you'd expect. I don't want to edit the bootstrap CSS, or Jquery.validate files as they will likely roll out an update at some-point.

Would I create a delegate, or a bind to the jquery functions and work from there. This is deep JS code which I'm not familiar with but could with time firefight my way through it.

Does any one know where I'd start with this problem, or know where it is implemented/been discussed?

Answer

Adam picture Adam · Apr 19, 2012
var page = function () {
    //Update that validator
    $.validator.setDefaults({
        highlight: function (element) {
            $(element).closest(".control-group").addClass("error");
        },
        unhighlight: function (element) {
            $(element).closest(".control-group").removeClass("error");
        }
    });
} ();

Finally, this fixed it for me. I hope this helps other people too...

My final JS ended like so.

$(function () {
    $('span.field-validation-valid, span.field-validation-error').each(function () {
        $(this).addClass('help-inline');
    });

    $('form').submit(function () {
        if ($(this).valid()) {
            $(this).find('div.control-group').each(function () {
                if ($(this).find('span.field-validation-error').length == 0) {
                    $(this).removeClass('error');
                }
            });
        }
        else {
            $(this).find('div.control-group').each(function () {
                if ($(this).find('span.field-validation-error').length > 0) {
                    $(this).addClass('error');
                }
            });
        }
    });


    $('form').each(function () {
        $(this).find('div.control-group').each(function () {
            if ($(this).find('span.field-validation-error').length > 0) {
                $(this).addClass('error');
            }
        });
    });

});


var page = function () {
    //Update that validator
    $.validator.setDefaults({
        highlight: function (element) {
            $(element).closest(".control-group").addClass("error");
        },
        unhighlight: function (element) {
            $(element).closest(".control-group").removeClass("error");
        }
    });
} ();