I'm creating a brand new MVC3 site.
Client side validation enabled on the web.config
<appSettings>
<add key="ClientValidationEnabled" value="true"/>
<add key="UnobtrusiveJavaScriptEnabled" value="true"/>
</appSettings>
Scenario #1: Output HTML generated after a failed (client side) validation:
<span data-valmsg-replace="true" data-valmsg-for="UserName" class="field-validation-error">
<span htmlfor="UserName" generated="true" class="">Please enter an email address</span>
</span>
Note the nested span tag where the innermost tag has a class=""
Scenario #2: Custom Server-side validation. With the same web.config configuration, I added a validation on the server to check for a custom business rule. The validation fails, I add the error to the ModelState.
The HTML generated looks like this:
<span data-valmsg-replace="true" data-valmsg-for="UserName" class="field-validation-error">Please enter a valid email address</span>
Note that just one span tag was generated, NOT a nested tag.
This behavior is making it a pain to deal with my CSS as I can't just style the .field-validation-error class as there are 2 different end results on my generated HTML.
IN SUMMARY: Client side validation generates just 1 span tag, server side validation generates 2 span tags.
QUESTION: Is this the indented behavior of the framework or am I doing something wrong?
Is this the indented behavior of the framework or am I doing something wrong?
You are not doing anything wrong. It's just how the jquery.validate.unobtrusive.js
script works. So you may call this a missing feature, discrepancy, PITA, whatever but that's how they did it out of the box.
This being said the jquery validate plugin is extensible and we can tweak it as we like:
$.validator.setDefaults({
// customize the way errors are shown
showErrors: function (errorMap, errorList) {
if (errorList.length < 1) {
// because we have customized the way errors are shown
// we need to clean them up if there aren't any
$('.field-validation-error', this.currentForm).hide().attr('class', 'field-validation-valid');
$('.input-validation-error', this.currentForm).removeClass('input-validation-error');
return;
}
$.each(errorList, function (index, error) {
// simply toggle the necessary classes to the corresponding span
// to make client validation generate the same markup as server
// side validation
var element = $(error.element);
element.attr('class', 'input-validation-error');
element.next('span').show().text(error.message).attr('class', 'field-validation-error');
})
}
});
If you want to always use nested spans for your validation messages after server validation failure (for styling reasons), you can do the following:
$(document).ready(function(){
$('.field-validation-error').each(function(){
$(this).html($('<span>').text($(this).text()));
});
});