jQuery.validate and Html.ValidationSummary playing nice together
A customer recently asked me how to get MVC with the MVC Futures project’s MicrosoftMvcJQueryValidation.js adapter file to play nicely with the Validation Summary HTML helper. It turns out that this functionality isn’t built into the adapter script file.
They also pointed me at this post by Soe Tun that gets things up and running. Soe changes the content of the script file to add this behaviour, relies on some non-public jQuery.validate functionality, and adds a custom Html.ValidationSummaryJQuery.
As I’m guessing that the adapter script will evolve to deal with this in the future and I don’t want the fact that I’m using jQuery to affect my server code, I felt the need to take a slightly different approach. What I really wanted was the ability to “patch” the behaviour right now with nothing more than a client-side only separate patch script, and to delete my patch script when it is no longer required, presumably also replacing the adapter script at the same time. I also wanted to avoid any features that aren’t public if at all possible.
The Solution
In the end I got this working by overriding the defaults for the validation library’s showErrors function. I had to use the approach of setting the defaults as I couldn’t actually intercept the construction and initialisation of the validator. The showErrors function only lists errors found during the current sweep of validation (and if that was triggered by an onblur event that will only ever be the current field) so I also had to get a list of all fields that are already marked invalid by scanning for those with a CSS class of “.input-validation-error”, and to combine that with the showErrors argument contents.
The end result is some script that looks like this;
// change the default showErrors behaviour
$.validator.setDefaults({
showErrors: function (errorMap, errorList) {
// Extracts existing field validation errors that
// are not necessarily part of the current validation phase.
// It's important to note that errorMap and errorList
// only contain failures from the current validation phase,
// so for example when you tab out of a field only that
// field is validated, and hence errorList will only
// ever contain a single error.
// Therefore this script combines this result with any
// previous failures already being displayed.
var map = {};
$('.input-validation-error').each(function () {
var element = this;
var txt = $('#' + element.id + '_validationMessage').text();
map[element.name] = txt;
});
// add the errors from this validation phase
// map will ensure they're unique as it's keyed on control name
$.extend(map, errorMap);
// convert all these unique errors into a nice simple array
var messages = [];
for (var item in map) {
messages[messages.length] = map[item];
}
// remove existing errors
clearErrors();
// display error list or hide validation summary
messages.length ? displayErrors(messages) : displaySuccess();
// let jQuery highlight the fields
this.defaultShowErrors();
}
This main function uses a few helper functions that are included in the download.
Of course there were also other issues – the adapter script “pops” the MVC metadata off an array so I have to interrogate that before the pop occurs, so the script must be in the right place (i.e. it must be called before document.ready).
Conclusion
All this adds up as a bit of a hack still and is by no means perfect; that’s why the jQuery adapter is in the Futures project and not the core product yet I guess. I still thought it was worth blogging though in case you find it useful – make sure you check out Soe’s approach too in case you prefer it.
I’ve attached an example solution so that you can see it in action and grab the full script. I’ve named the script “jquery-validate-mvc-patch.js”.
Anyone got a better solution than either of these? Do please feel free to propose something better as I’m not completely satisfied with this!
* Note this is a repost following the migration of our blogging platform
Comments
Anonymous
July 06, 2010
Thanks, this is exactly what I needed!Anonymous
September 27, 2010
Great job, but what happend when ValidationSummary ExcludePropertyErrors is true? In this case the validatior summary only must show the global message exluding the list of property errorsAnonymous
September 27, 2010
@ gdfuentes - Good question, I don't recall that property so I'm not sure if it's been added since? If not, I didn't test for it so it may need a bit more work. SimonAnonymous
January 27, 2011
If you're still reading this, make sure you check out MVC 3, as it has been rewritten to use the jQuery Validation Library... no doubt with nicer code than my hacking :)