web-dev-qa-db-fra.com

Utiliser la validation ASP.NET MVC avec jquery ajax?

J'ai simple action ASP.NET MVC comme ceci:

public ActionResult Edit(EditPostViewModel data)
{

}

Les EditPostViewModel ont des attributs de validation comme celui-ci:

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

Dans la vue, j'utilise les aides suivantes:

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

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

Si je soumets un formulaire, que cette zone de texte soit placée dans une validation, elle sera d'abord effectuée sur le client, puis sur le service (ModelState.IsValid).

Maintenant, j'ai quelques questions:

  1. Cela peut-il être utilisé avec jQuery ajax submit à la place? Ce que je fais est simplement de supprimer le formulaire et en cliquant sur le bouton "soumettre", un javascript recueillera des données, puis exécutera le $.ajax.

  2. Est-ce que le côté serveur ModelState.IsValid fonctionnera?

  3. Comment puis-je renvoyer le problème de validation au client et le présenter comme si je utilisais la validation build int (@Html.ValidationSummary(true))?

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

Modifier 1:

Inclus sur la page:

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

Côté client

Utiliser la bibliothèque jQuery.validate devrait être assez simple à configurer.

Spécifiez les paramètres suivants dans votre fichier Web.config:

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

Quand vous construisez votre vue, vous définissez des choses comme ceci:

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

REMARQUE: Celles-ci doivent être définies dans un élément de formulaire

Ensuite, vous devrez inclure les bibliothèques suivantes:

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

Cela devrait pouvoir vous configurer pour la validation côté client

Ressources

Du côté serveur

REMARQUE: Ceci ne concerne que la validation côté serveur supplémentaire au-dessus de la bibliothèque jQuery.validation.

Peut-être que quelque chose comme ceci pourrait aider:

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

ValidateAjax est un attribut défini comme suit:

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

Cela renvoie un objet JSON spécifiant toutes vos erreurs de modèle.

Exemple de réponse serait

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

Ceci serait renvoyé à votre callback de gestion d'erreur de l'appel $.ajax

Vous pouvez parcourir les données renvoyées pour définir les messages d'erreur en fonction des clés renvoyées (je pense que quelque chose comme $('input[name="' + err.key + '"]') trouverait votre élément d'entrée

147
Andrew Burgess

Ce que vous devez faire est de sérialiser vos données de formulaire et de les envoyer à l'action du contrôleur. ASP.NET MVC va lier les données de formulaire à l'objet EditPostViewModel (paramètre de votre méthode d'action), à l'aide de la fonction de liaison de modèle MVC.

Vous pouvez valider votre formulaire côté client et, si tout va bien, envoyer les données au serveur. La méthode valid() vous sera utile.

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

    });

});
39
Shyju

Voici une solution assez simple:

Dans le contrôleur, nous retournons nos erreurs comme ceci:

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

Voici quelques exemples du script client:

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

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

C'est comme ça que nous le gérons via 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);
        }
    }
});

De plus, je rends des vues partielles via ajax de la manière suivante:

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

Méthode 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();
        }
    }
8
Alex Herman

Ajout d’un peu plus de logique à la solution fournie par @Andrew Burgess. Voici la solution complète:

Création d'un filtre d'action pour obtenir des erreurs pour la demande 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;
            }
        }
    }

Ajout du filtre à ma méthode de contrôleur en tant que:

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

Ajout d'un script commun pour la validation de 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);
}

Enfin ajouté la méthode javascript error à mon formulaire Ajax Begin:

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

Vous pouvez le faire de cette façon:

(Edit: Considérant que vous attendez une réponse json avec 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');
    }
},

Si vous avez besoin, je peux aussi expliquer comment faire en renvoyant une erreur 500 et obtenir l'erreur dans l'événement event (ajax). Mais dans votre cas cela peut être une option

1
andres descalzo