JQuery Validate, ASP.NET MVC ModelState Ошибки (Async POST)
Я разрабатываю веб-приложение с asp.net mvc 3, и у меня есть некоторая форма POST для асинхронного действия (через ajax). Это действие возвращает ViewModel с некоторыми аннотациями данных для его проверки. Валидация работает нормально, но когда валидаторы возвращают ошибку, я не знаю, как я могу вернуть ее, чтобы показать ее на мой взгляд (потому что POST был сделан ajax).
Мое действие - это что-то вроде:
[HttpPost]
public ActionResult SaveCustomer(CustomerViewModel input) {
if (!ModelState.IsValid) { // <-- business validation
return Json(new { success = false, errors = ???});
}
// persist
return Json(new { success = true });
}
Как я могу показать эти ошибки с помощью проверки jquery на мой взгляд?
Если можно отправить какой-то код в образец... Я бы это заметил!
Спасибо, ребята!
Ответы
Ответ 1
Вместо того, чтобы отправлять JSON в случае ошибки, я бы поместил форму внутри частичного, а затем действие контроллера вернуло это частичное в случае ошибки. Проблема с JSON заключается в том, что вы действительно можете получить ошибки из ModelState с помощью LINQ, но это может быть PITA, чтобы показать их в представлении.
Итак:
<div id="myform">
@Html.Partial("_MyForm")
</div>
а затем внутри _MyForm.cshtml
:
@model CustomerViewModel
@using (Html.BeginForm())
{
@Html.EditorFor(x => x.Foo)
@Html.ValidationMessageFor(x => x.Foo)
<br />
@Html.EditorFor(x => x.Bar)
@Html.ValidationMessageFor(x => x.Bar)
<br />
<input type="submit" value="OK" />
}
и действие контроллера будет следующим:
[HttpPost]
public ActionResult SaveCustomer(CustomerViewModel model)
{
if (!ModelState.IsValid)
{
return PartialView("_MyForm", model);
}
return Json(new { success = true });
}
и последний шаг - AJAXify эту форму, которая может быть выполнена в отдельном файле javascript:
$(function () {
$('#myform').delegate('form', 'submit', function () {
$.ajax({
url: this.action,
type: this.method,
data: $(this).serialize(),
success: function (result) {
if (result.success) {
// We have a JSON object in case of success
alert('success');
} else {
// We have the partial with errors in case of failure
// so all we have to do is update the DOM
$('#myform').html(result);
}
}
});
return false;
});
});
Ответ 2
Вы можете вернуть ошибки ModelState. Это не проверено, но что-то вроде этого должно работать.
return Json(new
{
success = false,
errors = ModelState.Keys.SelectMany(k => ModelState[k].Errors)
.Select(m => m.ErrorMessage).ToArray()
});
Изменить: чтобы отображать ошибки в представлении, вы просто проверяете, были ли вы успешны, а если нет, перебирайте список ошибок и помещайте их там, где вы показываете свои ошибки.
if(!result.success) {
for(var error in result.errors) {
$('#errorMessages').append(error + '<br />');
}
}
Я предпочитаю ответ Дарина для большинства проектов, но ваш потребитель не всегда может быть вашим собственным приложением, и в этом случае возврат списка ошибок более уместен, поскольку он позволит потребителю отображать ошибки, но они хотят.
Ответ 3
Создайте класс для представления ошибок ModelState для отдельных свойств.
public class ValidationError
{
public string PropertyName = "";
public string[] ErrorList = null;
}
Создать метод, который возвращает список ValidationErrors на основе ModelState
public IEnumerable<ValidationError> GetModelStateErrors(ModelStateDictionary modelState)
{
var errors = (from m in modelState
where m.Value.Errors.Count() > 0
select
new ValidationError
{
PropertyName = m.Key,
ErrorList = (from msg in m.Value.Errors
select msg.ErrorMessage).ToArray()
})
.AsEnumerable();
return errors;
}
Затем в вашем контроллере Post Method сделайте:
if (!ModelState.IsValid)
{
return Json(new
{
errors = true,
errorList = GetModelStateErrors(ModelState)
}, JsonRequestBehavior.AllowGet);
}
Вы можете создать JS-функции, которые перебирают список ошибок, возвращенный выше.
$.ajax({
cache: false,
async: true,
type: "POST",
url: form.attr('action'),
data: form.serialize(),
success: function (data) {
if (data.errors) {
displayValidationErrors(data.errorList);
}
},
error: function (result) {
console.log("Error");
}
});
function displayValidationErrors(errors) {
$.each(errors, function (idx, validationError) {
$("span[data-valmsg-for='" + validationError.PropertyName + "']").text(validationError. ErrorList[0]);
});
}
В приведенном выше примере я получаю только первое сообщение об ошибке из ErrorList. Вы можете создать дополнительный цикл, чтобы получить все сообщения и добавить их к своему периоду проверки.
Ответ 4
Попробуйте этот код. Это простое решение вашей проблемы. Он объединит все ошибки состояния модели в одну строку.
[HttpPost]
public ActionResult SaveCustomer(CustomerViewModel input) {
if (!ModelState.IsValid) { // <-- business validation
return Json(new { success = false, errors = string.Join("; ", ModelState.Values
.SelectMany(x => x.Errors)
.Select(x => x.ErrorMessage));});
}
// persist
return Json(new { success = true });
}