Microsoft unobtrusive validation fails to work for our MVC 4.0 site when we upgrade the jQuery version from 1.7.1 to jQuery 1.9.
Attempted Fixes
These are fixes that I've tried, and some related posts that I read. But suggestions that I read here did not resolve the issue.
- MVC unobtrusive validation with JQuery 1.9 not working
- Unobtrusive Ajax stopped working after update jQuery to 1.9.0
- https://aspnetwebstack.codeplex.com/SourceControl/changeset/e6ea9683f1dbb107f5379e1de787abd046bc721a
- https://connect.microsoft.com/VisualStudio/feedback/details/776965/please-support-jquery-v1-9-0-properly-in-jquery-validate-unobtrusive
Background
We are in the process of upgrading an MVC 4.0 site to the latest version of jQuery. Part of our aim is to upgrade the other jQuery libraries on the site, like Bootstrap, to their respective latest versions. These upgrades will require later versions of jQuery, newer than the present version we currently employ (1.7.1). We would like to get this to jQuery 1.11, and for now I'm implementing the intermediate step of trying jQuery 1.9 and utilizing the JQMigrate script. I have read the suggested fix noted on GitHub for jQMigrate, but it's unclear to me how to implement this on the unobtrusive validation code. https://github.com/jquery/jquery-migrate/blob/master/warnings.md#jqmigrate-jqueryparsejson-requires-a-valid-json-string
Sample Code
Sample code showing changes for the onError and onSuccess functions in the 4.0 version of jquery.validate.unobtrusive.js are below. The original Microsoft implementation is noted in each case. Above that, the comments show some attempts we made to fix the original implementation, along with a corresponding link showing where the recommendation was obtained.
function onError(error, inputElement) { // 'this' is the form element
/*
// Codeplex fix from http://bit.ly/1xasYAq
var container = $(this).find("[data-valmsg-for='" + escapeAttributeValue(inputElement[0].name) + "']"),
replace = $.parseJSON(container.attr("data-valmsg-replace") || null) !== false;
// StackOverflow fix from http://bit.ly/1tKjGqS
var container = $(this).find("[data-valmsg-for='" + escapeAttributeValue(inputElement[0].name) + "']"),
replace = container.attr("data-valmsg-replace") && $.parseJSON(container.attr("data-valmsg-replace")) !== false;
*/
// Original Microsoft implementation
var container = $(this).find("[data-valmsg-for='" + escapeAttributeValue(inputElement[0].name) + "']"),
replaceAttrValue = container.attr("data-valmsg-replace"),
replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) !== false : null;
container.removeClass("field-validation-valid").addClass("field-validation-error");
error.data("unobtrusiveContainer", container);
if (replace) {
container.empty();
error.removeClass("input-validation-error").appendTo(container);
}
else {
error.hide();
}
}
function onSuccess(error) { // 'this' is the form element
/*
// Codeplex fix from http://bit.ly/1xasYAq
var container = error.data("unobtrusiveContainer"),
replace = $.parseJSON(container.attr("data-valmsg-replace") || null);
// StackOverflow fix from http://bit.ly/1tKjGqS
var container = error.data("unobtrusiveContainer"),
replace = container.attr("data-valmsg-replace") && $.parseJSON(container.attr("data-valmsg-replace"));
*/
// Original Microsoft implementation.
var container = error.data("unobtrusiveContainer"),
replaceAttrValue = container.attr("data-valmsg-replace"),
replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) : null;
if (container) {
container.addClass("field-validation-valid").removeClass("field-validation-error");
error.removeData("unobtrusiveContainer");
if (replace) {
container.empty();
}
}
}
These are the controls from the view.
@Html.TextBoxFor(m => m.DealerAccountNumber)
@Html.ValidationMessageFor(m => m.DealerAccountNumber)
These are the data annotations in our model.
[Required(ErrorMessage = "Dealer is required")]
[RegularExpression(@"[a-zA-Z0-9]*", ErrorMessage = "Not a valid dealer number")]
[Display(Name = "Account")]
[Remote("ValidateDealerAccountNumber", "Registration", ErrorMessage = "Dealer was not found")]
public string DealerAccountNumber { get; set; }
This is the remote validator in our controller.
public virtual ActionResult ValidateDealerAccountNumber(Dealer dealer)
{
var success = (dealer != null);
return Json(success, JsonRequestBehavior.AllowGet);
}
Upon entering an invalid dealer number, the JQMigrate script shows the following warning:
JQMIGRATE: jQuery.parseJSON requires a valid JSON string jquery-migrate-1.2.1.js:41
console.trace() jquery-migrate-1.2.1.js:43
migrateWarn jquery-migrate-1.2.1.js:43
jQuery.parseJSON jquery-migrate-1.2.1.js:232
q jquery.js:8197
r jquery.js:8000
r jquery.js:8558
My understanding is that Microsoft corrected this problem in MVC 5.0, but we presently lack the luxury of upgrading our entire site from MVC 4.0 to MVC 5.0 and performing a full regression test. The unobtrusive validation of course works as long as we reference JQMigrate, but we don't want that dependency.
Presently I'm using a local copy of the jquery.validate.unobtrusive.js file, version 4.0, in this project, as originally copied from http://ajax.aspnetcdn.com/ajax/mvc/4.0/jquery.validate.unobtrusive.js.
In that file I've replaced andSelf() with addBack(), to align with the latest version of jQuery. And I've attempted the changes commented out in the onError and onSuccess functions noted in the first code block above. But none of that worked.
Thanks for your help.