Verwenden Sie die ASP.NET MVC-Validierung mit jquery ajax?

119

Ich habe eine einfache ASP.NET MVC-Aktion wie folgt:

public ActionResult Edit(EditPostViewModel data)
{

}

Sie EditPostViewModelhaben folgende Validierungsattribute:

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

In der Ansicht verwende ich die folgenden Helfer:

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

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

Wenn ich auf einem Formular sende, dass dieses Textfeld in eine Validierung eingefügt wird, erfolgt dies zuerst auf dem Client und dann auf service ( ModelState.IsValid).

Jetzt habe ich ein paar Fragen:

  1. Kann dies stattdessen mit jQuery ajax submit verwendet werden? Ich entferne einfach das Formular und wenn ich auf die Schaltfläche "Senden" klicke, sammelt ein Javascript Daten und führt das aus $.ajax.

  2. Funktioniert die Serverseite ModelState.IsValid?

  3. Wie kann ich das Validierungsproblem an den Client zurückleiten und so präsentieren, als würde ich die build int validation ( @Html.ValidationSummary(true)) verwenden?

Beispiel für einen Ajax-Aufruf:

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');
        }
    });
}

Bearbeiten 1:

Auf Seite enthalten:

<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>
Efeu
quelle
Schöne Antwort unten. Hier ist eine verwandte Frage. Die Antwort ermöglicht eine clientseitige oder serverseitige Validierung. Ich bin verliebt in den JQuery-Code, den sie bereitstellen. (Nein, es war nicht meine Antwort.) Stackoverflow.com/questions/28987752/…
Abenteuer

Antworten:

155

Client-Seite

Die Verwendung der jQuery.validateBibliothek sollte ziemlich einfach einzurichten sein.

Geben Sie die folgenden Einstellungen in Ihrer Web.configDatei an:

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

Wenn Sie Ihre Ansicht aufbauen, definieren Sie Folgendes:

@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)

HINWEIS: Diese müssen innerhalb eines Formularelements definiert werden

Dann müssten Sie die folgenden Bibliotheken einschließen:

<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>

Dies sollte Sie für die clientseitige Validierung einrichten können

Ressourcen

Serverseite

HINWEIS: Dies dient nur zur zusätzlichen serverseitigen Überprüfung über der jQuery.validationBibliothek

Vielleicht könnte so etwas helfen:

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

Wo ValidateAjaxist ein Attribut definiert als:

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;
        }
    }
}

Dadurch wird ein JSON-Objekt zurückgegeben, das alle Ihre Modellfehler angibt.

Beispiel Antwort wäre

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

Dies wird an Ihren Fehlerbehandlungsrückruf des $.ajaxAnrufs zurückgegeben

Sie können die zurückgegebenen Daten durchlaufen, um die Fehlermeldungen basierend auf den zurückgegebenen Schlüsseln nach Bedarf festzulegen (ich denke, so etwas $('input[name="' + err.key + '"]')würde Ihr Eingabeelement finden

Andrew Burgess
quelle
1
Tolle Antwort, besonders mit dem fantastischen ValidateAjaxAttribute! Danke dir!
René
3
Ich verstehe nicht, warum diese Antwort so viele Stimmen bekommen hat. Frage 1 wird nicht beantwortet: Wie wird die Client-Validierung beim Posten mit $ .ajax durchgeführt? Ich denke, @Shyju Antwort hilft dabei.
Valentin
2
@Valentin - meine Antwort hilft jedoch, da die Daten auch serverseitig validiert werden. Die Validierungs-Plugins sollten die dynamische Validierung beim Ausfüllen des Formulars ermöglichen. Wenn das Formular gesendet wird (das OP möchte dies jedoch tun), stellt der Server die endgültige Validierung bereit, was auf jeden Fall vorzuziehen ist, da die clientseitige Validierung umgangen werden kann.
Andrew Burgess
8
Ich verwende die Validierungsnachrichtenspannen von jQuery, indem ich die zurückgegebenen Fehler durchlaufe und die Fehlermeldung in die richtige Spanne einfüge:for (var i = 0; i < modelStateErrors.length; i++) { $('span[data-valmsg-for="' + modelStateErrors[i].key + '"]').text(modelStateErrors[i].errors[0]); }
Ian
7
Diese Antwort ist großartig! Ich denke jedoch immer noch, dass das ASP.NET MVC-Framework eine integrierte Möglichkeit bieten sollte, dies zu tun.
Zignd
40

Sie sollten Ihre Formulardaten serialisieren und an die Controller-Aktion senden. ASP.NET MVC bindet die Formulardaten EditPostViewModelmithilfe der MVC-Modellbindungsfunktion an das Objekt (Ihren Aktionsmethodenparameter).

Sie können Ihr Formular auf Clientseite validieren und die Daten an den Server senden, wenn alles in Ordnung ist. Die valid()Methode wird sich als nützlich erweisen.

$(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
           })
        }

    });

});
Shyju
quelle
1
Vielen Dank! Ich habe versucht, dieses $ ("form #" + formId) .validate (), aber es sagt, dass das Formular (das gefunden wird) kein validate () hat?
Ivy
Siehe Bearbeiten1, wo ich zeige, dass das Validierungsskript auf der Webseite enthalten ist. Ich sehe auch, dass die Validierung ausgeführt wird, wenn eine normale Schaltfläche zum Senden des Eingabetyps verwendet wird.
Ivy
Ich habe das Problem gefunden (Scripts.Render von der Masterseite entfernt). Haben Sie dennoch Probleme, ModelState-Validierungsfehler an den Client zurückzusenden? Wie soll ich das handhaben? Zum Beispiel, wenn der Benutzer nicht mehr angemeldet ist (ModelState.AddModelError ("CustomError", "Validierungstext").
Ivy
1
Sie müssen die js-Dateien jquery.validate und jquery.validate.unobtrusive in Ihre Seite aufnehmen. Haben Ihre HTML-Eingaben das Attribut, nach dem Validierungs-Plugins suchen?
Shyju
1
Ivy: Ihr Rückgabetyp (ActionResult) ist eine Basisklasse von JsonResult. So kann es JSON-Daten zurückgeben. Wenn es sich um einen Ajax-Aufruf handelt (überprüfen Sie Request.IsAjax), rufen Sie die Validierungsfehler ab, erstellen Sie einen JSON und senden Sie ihn an den Client zurück. Überprüfen Sie den JSON in der Rückrufmethode von $ .post und zeigen Sie die Fehlermeldungen an.
Shyju
9

Hier ist eine ziemlich einfache Lösung:

In der Steuerung geben wir unsere Fehler folgendermaßen zurück:

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

Hier sind einige der Client-Skripte:

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

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

So gehen wir mit Ajax um:

$.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);
        }
    }
});

Außerdem rendere ich Teilansichten über Ajax folgendermaßen:

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

RenderRazorViewToString-Methode:

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();
        }
    }
Alex Herman
quelle
3
Ihre "GetModelStateErrors" können vollständig vereinfacht werden, indem Sie sie in eine einfachere einzeilige Anweisung konvertieren
Camilo Terevinto
1
Warum nicht einfach ein zurückgeben PartialView, um es an Ajax zu rendern?
Sinjai
4

Der von @Andrew Burgess bereitgestellten Lösung wurde etwas mehr Logik hinzugefügt. Hier ist die vollständige Lösung:

Erstellt einen Aktionsfilter, um Fehler für Ajax-Anforderungen zu erhalten:

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;
            }
        }
    }

Der Filter wurde zu meiner Controller-Methode hinzugefügt als:

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

Ein allgemeines Skript für die JQuery-Validierung wurde hinzugefügt:

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);
}

Schließlich wurde die Fehler-Javascript-Methode zu meinem Ajax-Startformular hinzugefügt:

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

Sie können es so machen:

( Bearbeiten: In Anbetracht dessen, dass Sie auf eine Antwort jsonmit warten dataType: 'json')

.NETZ

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');
    }
},

Wenn Sie brauchen, kann ich Ihnen auch erklären, wie es geht, indem Sie einen Fehler 500 zurückgeben und den Fehler im Ereignisfehler (Ajax) erhalten. In Ihrem Fall kann dies jedoch eine Option sein

andres descalzo
quelle
1
Ich weiß, wie man eine reguläre Jason-Anfrage ausführt. Dies hilft mir jedoch nicht bei der Validierung der verschiedenen Eigenschaften oder verwendet sogar die von mir angeforderte integrierte ASP.NET MVC-Validierung. Ich könnte wahrscheinlich ein komplexes Jason-Objekt erstellen, um die Validierungsfehler für jedes Objekt zu erklären, aber dies wird eine Menge Arbeit bedeuten, und ich hoffe, dass Sie die integrierte Funktionalität der ASP.NET MVC-Validierung dafür wiederverwenden können?
Ivy
1 - Wie führe ich meine Funktion "SendPost" aus? Und 2 - Ihre gültigen Daten auf dem Client?
andres descalzo
Bitte erklären? Hast du deinen letzten Beitrag nicht bekommen?
Ivy