This is draft code but the same idea works for me in production.
The main idea here is that Json errors have predefined tag names, that no normal objects will have. For errors validation errors HTML is re-created using JavaScript (both top summary and form elements highlighting).
Server side:
public static JsonResult JsonValidation(this ModelStateDictionary state)
{
return new JsonResult
{
Data = new
{
Tag = "ValidationError",
State = from e in state
where e.Value.Errors.Count > 0
select new
{
Name = e.Key,
Errors = e.Value.Errors.Select(x => x.ErrorMessage)
.Concat(e.Value.Errors.Where(x => x.Exception != null).Select(x => x.Exception.Message))
}
}
};
}
in action:
if (!ModelState.IsValid && Request.IsAjaxRequest())
return ModelState.JsonValidation();
Client side:
function getValidationSummary() {
var el = $(".validation-summary-errors");
if (el.length == 0) {
$(".title-separator").after("<div><ul class='validation-summary-errors ui-state-error'></ul></div>");
el = $(".validation-summary-errors");
}
return el;
}
function getResponseValidationObject(response) {
if (response && response.Tag && response.Tag == "ValidationError")
return response;
return null;
}
function CheckValidationErrorResponse(response, form, summaryElement) {
var data = getResponseValidationObject(response);
if (!data) return;
var list = summaryElement || getValidationSummary();
list.html('');
$.each(data.State, function(i, item) {
list.append("<li>" + item.Errors.join("</li><li>") + "</li>");
if (form && item.Name.length > 0)
$(form).find("*[name='" + item.Name + "']").addClass("ui-state-error");
});
}
$.ajax(... function(response) {
CheckValidationErrorResponse(xhr.responseText); } );
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…