jQuery valider, ASP.NET erreurs MVC ModelState (POST asynchrone)

Je développe une application web avec asp.net mvc 3 et j'ai une forme qui POST à une action asynchrone (via ajax). Cette action recive un ViewModel avec quelques annotations de données pour le valider. La validation fonctionne bien mais quand les validateurs renvoient une erreur, je ne sais pas comment puis-je la renvoyer pour montrer à mon avis (parce que le POST a été fait par ajax).

Mon action est quelque chose comme:

[HttpPost]
public ActionResult SaveCustomer(CustomerViewModel input) {
    if (!ModelState.IsValid) { // <-- business validation
        return Json(new { success = false, errors = ???});
    }
    // persist 
    return Json(new { success = true });
}

Comment puis-je montrer ces erreurs avec jQuery validate à mon avis? S'il est possible de poster du code échantillonner... Je appretiate que!

Merci Les gars!

21
demandé sur Felipe Oriani 2011-09-02 21:56:27

3 réponses

Au lieu d'envoyer JSON en cas d'erreur, je mettrais le formulaire dans un partiel, puis l'action du contrôleur retournerait ce partiel en cas d'erreur. Le problème avec JSON est que vous pouvez en fait récupérer les erreurs du ModelState en utilisant LINQ, mais cela pourrait être un PITA pour les afficher sur la vue.

Donc:

<div id="myform">
    @Html.Partial("_MyForm")
</div>

Et puis à l'intérieur _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" />
}

Et l'action du contrôleur deviendrait:

[HttpPost]
public ActionResult SaveCustomer(CustomerViewModel model)
{
    if (!ModelState.IsValid)
    {
        return PartialView("_MyForm", model);
    }
    return Json(new { success = true });
}

Et la dernière étape consiste à Ajaxifier ce formulaire qui pourrait être fait dans un fichier javascript séparé:

$(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;
    });
});
45
répondu Darin Dimitrov 2011-09-02 18:17:25

Vous pouvez renvoyer les erreurs ModelState. Ce n'est pas testé, mais quelque chose comme ça devrait fonctionner.

return Json(new
            {
                success = false,
                errors = ModelState.Keys.SelectMany(k => ModelState[k].Errors)
                                .Select(m => m.ErrorMessage).ToArray()
            });

Edit: pour afficher les erreurs dans une vue, vérifiez simplement si vous avez réussi, et sinon, parcourez la liste des erreurs et placez-les là où vous montrez vos erreurs.

if(!result.success) {
    for(var error in result.errors) {
        $('#errorMessages').append(error + '<br />');
    }
}

Je préfère la réponse de Darin pour la plupart des projets, mais votre consommateur peut ne pas toujours être votre propre application, auquel cas renvoyer une liste d'erreurs est plus approprié car cela permettrait consommateur pour afficher les erreurs comme ils le souhaitent.

13
répondu Timothy Strimple 2015-08-27 17:43:58

Créez une classe pour représenter les erreurs ModelState pour les propriétés individuelles.

public class ValidationError
{

    public string PropertyName = "";
    public string[] ErrorList = null;
}

Crée une méthode qui renvoie une liste de ValidationErrors basée sur 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;
    }

Ensuite, dans votre méthode de poste de contrôleur, faites:

        if (!ModelState.IsValid)
        {
            return Json(new
            {
                errors = true,
                errorList = GetModelStateErrors(ModelState)
            }, JsonRequestBehavior.AllowGet);
        }

Vous pouvez créer des fonctions JS qui parcourent la liste d'erreurs renvoyée ci-dessus

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

    });
}

Dans l'exemple ci-dessus, je ne reçois que le premier message d'erreur de 'ErrorList'. Vous pouvez créer une boucle supplémentaire pour obtenir tous les messages et ajouter à votre durée de validation.

0
répondu Asaad 2018-09-09 11:49:13