I've got a form that is using unobtrusive JQuery validation along with a validation summary. It works great. However, this form does an Ajax POST which returns a JSON result. If the result == true, then I continue. However, if the JSON result returns an array of messages, I want to fire the form validation in order to update the fields. Errors are returned as follows:
{
"errors": [
{ "key" : "NameFirst", "message": "This is the message" },
{ "key" : "NameLast", "message": "This is the message" }
]
}
I parse the JSON result and call showErrors() like so:
for (var j = 0; j < response.errors.length; j++) {
var key = response.errors[j].key;
var error = {};
error[key] = response.errors[j].message;
$form.data('validator').showErrors(error);
}
This correctly highlights the fields, but it doesn't update the validation summary. How can I get that to update?
Also, sometimes the errors are generic and don't map to a specific property/field in the model. In that case, they are returned with null keys like:
{
"errors": [
{ "key" : null, "message": "This is the message" },
{ "key" : null, "message": "This is the other message" },
{ "key" : "NameFirst", "message": "This is the message" },
{ "key" : "NameLast", "message": "This is the message" }
]
}
I can't call showErrors on those because they don't map to a field identifier. Once I'm told how to update the summary, I sure I can append items to the list for the generic messages, but I'm open to other suggestions. Thanks!
UPDATE
Here is what I ended up doing that seems to work quite well. I have to build the summary manually in addition to calling showErrors on the valid keyed errors:
var $summary = $form.find("[data-valmsg-summary=true]")
.addClass("validation-summary-errors")
.removeClass("validation-summary-valid");
var $ul = $summary.find("ul").empty();
var error = {};
$.each(response.errors, function () {
if (this.key)
error[this.key] = this.message;
$("<li />").html(this.message).appendTo($ul);
});
$form.validate().showErrors(error);
I hope this helps others.
I needed to add my own custom error messages to the summary list. After a day or so perusing the jQuery validate and unobtrusive validation source code here is the solution I ended up using.
First I declared my form
@using (Html.BeginForm(null, null, FormMethod.Post, new {id = "formA"}))
{
@Html.ValidationSummary()
.....
.....
Setting the id is important as I use this id in the javascript code to retrieve the form object.
I used the following code to update the summary error list on submit
$(function () {
var formValidator,
$form = $("#formA");
// add handler to the forms submit action
$form.submit(function () {
if (!formValidator) {
formValidator = $form.validate({}); // Get existing jquery validate object
}
var errorList = [];
// get existing summary errors from jQuery validate
$.each(formValidator.errorList, function (index, errorListItem) {
errorList.push(errorListItem.message);
});
// add our own errors
if (testForErrorCondidtionA()) {
errorList.push("Please fix error condition A!");
}
if (testForErrorCondidtionB()) {
errorList.push("Please fix error condition B!");
}
// No errors, do nothing
if (0 === errorList.length) {
return true; // allow submit
}
// find summary div
var $summary = $form.find("[data-valmsg-summary=true]");
// find the unordered list
var $ul = $summary.find("ul");
// Clear existing errors from DOM by removing all element from the list
$ul.empty();
// Add all errors to the list
$.each(errorList, function (index, message) {
$("<li />").html(message).appendTo($ul);
});
// Add the appropriate class to the summary div
$summary.removeClass("validation-summary-valid")
.addClass("validation-summary-errors");
return false; // Block the submit
});
});
This submit handler is always called after the unobtrusive handler, which means the summary error list we retrieve from jQuery validate will always be up to date.
Hope this answer helps as unobtrusive validation can get hairy once you veer away form the standard case(s).