Використовувати перевірку ASP.NET MVC з jquery ajax?


119

У мене прості дії ASP.NET MVC на зразок цього:

public ActionResult Edit(EditPostViewModel data)
{

}

EditPostViewModelМають атрибути перевірки , як це:

[Display(Name = "...", Description = "...")]
[StringLength(100, MinimumLength = 3, ErrorMessage = "...")]
[Required()]
public string Title { get; set; }

У поданні я використовую таких помічників:

 @Html.LabelFor(Model => Model.EditPostViewModel.Title, true)

 @Html.TextBoxFor(Model => Model.EditPostViewModel.Title, 
                        new { @class = "tb1", @Style = "width:400px;" })

Якщо я надішлю форму на тему, що це текстове поле поміщене у валідацію, буде зроблено спочатку на клієнті, а потім на службі ( ModelState.IsValid).

Тепер у мене є кілька питань:

  1. Чи можна це використовувати замість подання jQuery ajax? Що я роблю, це просто видалити форму, а після натискання кнопки "Надіслати" javascript збирає дані, а потім запускає $.ajax.

  2. Чи буде ModelState.IsValidпрацювати сервер ?

  3. Як я можу переслати проблему валідації назад клієнтові та подати її так, ніби я використовую валідацію int validation ( @Html.ValidationSummary(true))?

Приклад виклику Ajax:

function SendPost(actionPath) {
    $.ajax({
        url: actionPath,
        type: 'POST',
        dataType: 'json',
        data:
        {
            Text: $('#EditPostViewModel_Text').val(),
            Title: $('#EditPostViewModel_Title').val() 
        },
        success: function (data) {
            alert('success');
        },
        error: function () {
            alert('error');
        }
    });
}

Редагувати 1:

Включено на сторінку:

<script src="/Scripts/jquery-1.7.1.min.js"></script>
<script src="/Scripts/jquery.validate.min.js"></script>
<script src="/Scripts/jquery.validate.unobtrusive.min.js"></script>

Приємна відповідь нижче. Ось пов'язане питання. Відповідь дозволяє перевірити клієнтську чи серверну перевірку. Я закоханий у код JQuery, який вони надають. (Ні, це не була моя відповідь.) Stackoverflow.com/questions/28987752/…
Пригода

Відповіді:


155

Сторона клієнта

Використання jQuery.validateбібліотеки має бути досить простим у налаштуванні.

Вкажіть у Web.configфайлі такі параметри :

<appSettings>
    <add key="ClientValidationEnabled" value="true"/> 
    <add key="UnobtrusiveJavaScriptEnabled" value="true"/> 
</appSettings>

Створюючи свій погляд, ви визначаєте такі речі:

@Html.LabelFor(Model => Model.EditPostViewModel.Title, true)
@Html.TextBoxFor(Model => Model.EditPostViewModel.Title, 
                                new { @class = "tb1", @Style = "width:400px;" })
@Html.ValidationMessageFor(Model => Model.EditPostViewModel.Title)

ПРИМІТКА. Їх потрібно визначити в елементі форми

Тоді вам потрібно буде включити такі бібліотеки:

<script src='@Url.Content("~/Scripts/jquery.validate.js")' type='text/javascript'></script>
<script src='@Url.Content("~/Scripts/jquery.validate.unobtrusive.js")' type='text/javascript'></script>

Це має бути в змозі налаштувати вас на перевірку на стороні клієнта

Ресурси

Сторона сервера

ПРИМІТКА. Це лише для додаткової перевірки на сервері на вершині jQuery.validationбібліотеки

Можливо, щось подібне могло б допомогти:

[ValidateAjax]
public JsonResult Edit(EditPostViewModel data)
{
    //Save data
    return Json(new { Success = true } );
}

Де ValidateAjaxатрибут визначається як:

public class ValidateAjaxAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        if (!filterContext.HttpContext.Request.IsAjaxRequest())
            return;

        var modelState = filterContext.Controller.ViewData.ModelState;
        if (!modelState.IsValid)
        {
            var errorModel = 
                    from x in modelState.Keys
                    where modelState[x].Errors.Count > 0
                    select new
                           {
                               key = x,
                               errors = modelState[x].Errors.
                                                      Select(y => y.ErrorMessage).
                                                      ToArray()
                           };
            filterContext.Result = new JsonResult()
                                       {
                                           Data = errorModel
                                       };
            filterContext.HttpContext.Response.StatusCode = 
                                                  (int) HttpStatusCode.BadRequest;
        }
    }
}

Це означає повернути об'єкт JSON із зазначенням усіх ваших помилок моделі.

Приклад відповіді буде

[{
    "key":"Name",
    "errors":["The Name field is required."]
},
{
    "key":"Description",
    "errors":["The Description field is required."]
}]

Це буде повернуто до вашої помилки при обробці зворотного $.ajaxдзвінка

Ви можете провести циклічну передачу через повернуті дані, щоб встановити повідомлення про помилки за потребою на основі повернутих ключів (я думаю, щось подібне $('input[name="' + err.key + '"]')знайде ваш елемент введення


1
Відмінна відповідь, особливо з дивовижним ValidateAjaxAttribute! Дякую!
Рене

3
Я не розумію, чому ця відповідь отримала стільки голосів. Він не відповідає на питання 1: як зробити перевірку клієнта під час публікації за допомогою $ .ajax? Я думаю, що відповідь @Shyju допомагає в цьому.
Валентин

2
@Valentin - моя відповідь допомагає, тому що дані також перевірені на стороні сервера. Плагіни перевірки повинні включати динамічну перевірку, коли форма заповнена, і коли форма буде подана (однак ОП хоче цього зробити), сервер надасть остаточну перевірку, яка є кращою в будь-якому випадку, оскільки перевірку на стороні клієнта можна обійти.
Ендрю Берджес

8
Я використовую повідомлення про перевірку jQuery, переглядаючи повернені помилки та вставляючи повідомлення про помилку в правильний проміжок часу:for (var i = 0; i < modelStateErrors.length; i++) { $('span[data-valmsg-for="' + modelStateErrors[i].key + '"]').text(modelStateErrors[i].errors[0]); }
Ян

7
Ця відповідь чудова! Але я все ж думаю, що рамка MSP для ASP.NET повинна забезпечувати вбудований спосіб цього робити.
Зігнд

40

Що вам слід зробити, це серіалізувати свої форми форми та надіслати їх до дії контролера. ASP.NET MVC прив’яже дані форми до EditPostViewModelоб'єкта (параметр методу дії), використовуючи функцію прив’язки моделі MVC.

Ви можете підтвердити свою форму на стороні клієнта, і якщо все в порядку, надішліть дані на сервер. valid()Метод знадобиться.

$(function () {

    $("#yourSubmitButtonID").click(function (e) {

        e.preventDefault();
        var _this = $(this);
        var _form = _this.closest("form");

        var isvalid = _form .valid();  // Tells whether the form is valid

        if (isvalid)
        {           
           $.post(_form.attr("action"), _form.serialize(), function (data) {
              //check the result and do whatever you want
           })
        }

    });

});

1
Дякую! Я спробував це $ ("form #" + formId) .validate (), але в ньому сказано, що форма (яка знайдена) не має валідату ()?
Плющ

Див. Редагування1, де я показую, що перевірений сценарій включений на веб-сторінку. Я також бачу, що перевірка працює при використанні звичайної кнопки введення типу введення.
Ivy

Я знайшов проблему (видалено Scripts.Render з головної сторінки). Але все ще виникають проблеми з поверненням клієнта помилок перевірки ModelState? Як я маю намір це вирішити? Наприклад, якщо користувач більше не входить у систему (ModelState.AddModelError ("CustomError", "текст перевірки").
Ivy,

1
вам потрібно включити на свою сторінку файли jquery.validate та jquery.validate.unobtrusive js. Чи є у ваших HTML-атрибутів атрибут, який слід шукати у плагінах перевірки?
Shyju

1
Плющ: Ваш тип повернення (ActionResult) є базовим класом JsonResult. щоб він міг повертати дані JSON. Що вам слід зробити, якщо це виклик Ajax (перевірте Request.IsAjax), отримайте помилки перевірки та складіть JSON та відправте його назад клієнту. Перевірте json у методі зворотного виклику $ .post та покажіть повідомлення про помилки.
Shyju

9

Ось досить просте рішення:

У контролері ми повертаємо наші помилки так:

if (!ModelState.IsValid)
        {
            return Json(new { success = false, errors = ModelState.Values.SelectMany(x => x.Errors).Select(x => x.ErrorMessage).ToList() }, JsonRequestBehavior.AllowGet);
        }

Ось деякі сценарії клієнта:

function displayValidationErrors(errors)
{
    var $ul = $('div.validation-summary-valid.text-danger > ul');

    $ul.empty();
    $.each(errors, function (idx, errorMessage) {
        $ul.append('<li>' + errorMessage + '</li>');
    });
}

Ось як ми впораємося з цим через ajax:

$.ajax({
    cache: false,
    async: true,
    type: "POST",
    url: form.attr('action'),
    data: form.serialize(),
    success: function (data) {
        var isSuccessful = (data['success']);

        if (isSuccessful) {
            $('#partial-container-steps').html(data['view']);
            initializePage();
        }
        else {
            var errors = data['errors'];

            displayValidationErrors(errors);
        }
    }
});

Також я надаю часткові перегляди через ajax таким чином:

var view = this.RenderRazorViewToString(partialUrl, viewModel);
        return Json(new { success = true, view }, JsonRequestBehavior.AllowGet);

Метод RenderRazorViewToString:

public string RenderRazorViewToString(string viewName, object model)
    {
        ViewData.Model = model;
        using (var sw = new StringWriter())
        {
            var viewResult = ViewEngines.Engines.FindPartialView(ControllerContext,
                                                                     viewName);
            var viewContext = new ViewContext(ControllerContext, viewResult.View,
                                         ViewData, TempData, sw);
            viewResult.View.Render(viewContext, sw);
            viewResult.ViewEngine.ReleaseView(ControllerContext, viewResult.View);
            return sw.GetStringBuilder().ToString();
        }
    }

3
Ваші "GetModelStateErrors" можна повністю спростити, перетворивши їх у спосіб більш простий однорядковий оператор: return ModelState.Values.SelectMany (x => x.Errors) .Select (x => x.ErrorMessage) .ToList ();
Каміло Теревінто

1
Чому б просто не повернути " PartialViewАякс" для надання?
Сінджай

4

Додано ще трохи логіки до рішення, яке надає @Andrew Burgess. Ось повне рішення:

Створено фільтр дій, щоб отримати помилки для запиту ajax:

public class ValidateAjaxAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            if (!filterContext.HttpContext.Request.IsAjaxRequest())
                return;

            var modelState = filterContext.Controller.ViewData.ModelState;
            if (!modelState.IsValid)
            {
                var errorModel =
                        from x in modelState.Keys
                        where modelState[x].Errors.Count > 0
                        select new
                        {
                            key = x,
                            errors = modelState[x].Errors.
                                                          Select(y => y.ErrorMessage).
                                                          ToArray()
                        };
                filterContext.Result = new JsonResult()
                {
                    Data = errorModel
                };
                filterContext.HttpContext.Response.StatusCode =
                                                      (int)HttpStatusCode.BadRequest;
            }
        }
    }

Доданий фільтр до мого методу контролера як:

[HttpPost]
// this line is important
[ValidateAjax]
public ActionResult AddUpdateData(MyModel model)
{
    return Json(new { status = (result == 1 ? true : false), message = message }, JsonRequestBehavior.AllowGet);
}

Додано загальний сценарій для перевірки jquery:

function onAjaxFormError(data) {
    var form = this;
    var errorResponse = data.responseJSON;
    $.each(errorResponse, function (index, value) {
        // Element highlight
        var element = $(form).find('#' + value.key);
        element = element[0];
        highLightError(element, 'input-validation-error');

        // Error message
        var validationMessageElement = $('span[data-valmsg-for="' + value.key + '"]');
        validationMessageElement.removeClass('field-validation-valid');
        validationMessageElement.addClass('field-validation-error');
        validationMessageElement.text(value.errors[0]);
    });
}

$.validator.setDefaults({
            ignore: [],
            highlight: highLightError,
            unhighlight: unhighlightError
        });

var highLightError = function(element, errorClass) {
    element = $(element);
    element.addClass(errorClass);
}

var unhighLightError = function(element, errorClass) {
    element = $(element);
    element.removeClass(errorClass);
}

Нарешті додано метод JavaScript з помилками до моєї форми початку Ajax:

@model My.Model.MyModel
@using (Ajax.BeginForm("AddUpdateData", "Home", new AjaxOptions { HttpMethod = "POST", OnFailure="onAjaxFormError" }))
{
}

1

Ви можете це зробити так:

( Edit: З огляду на , що ви чекаєте відповіді jsonз dataType: 'json')

.NET

public JsonResult Edit(EditPostViewModel data)
{
    if(ModelState.IsValid) 
    {
       // Save  
       return Json(new { Ok = true } );
    }

    return Json(new { Ok = false } );
}

JS:

success: function (data) {
    if (data.Ok) {
      alert('success');
    }
    else {
      alert('problem');
    }
},

Якщо вам потрібно, я також можу пояснити, як це зробити, повернувши помилку 500, і отримати помилку в помилці події (ajax). Але у вашому випадку це може бути варіант


1
Я знаю, як робити звичайний запит Джейсона, однак це не допоможе мені перевірити різні властивості або навіть використовувати вбудовану в ASP.NET перевірку MVC, яку я попросив. Можливо, я міг би створити складний об’єкт Джейсона, щоб пояснити помилки перевірки для кожного власника, але це буде багато роботи, і я сподіваюся, що ви можете використати для цього вбудовану функціональність перевірки ASP.NET MVC?
Плющ

1 - Як запустити функцію "SendPost" ?, І 2 - ваші дійсні дані про клієнта?
andres descalzo

Прохання пояснити? Не отримаєте останнє повідомлення?
Плющ
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.