Gunakan validasi ASP.NET MVC dengan jquery ajax?

119

Saya memiliki tindakan ASP.NET MVC sederhana seperti ini:

public ActionResult Edit(EditPostViewModel data)
{

}

The EditPostViewModelmemiliki atribut validasi seperti ini:

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

Dalam tampilan saya menggunakan pembantu berikut:

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

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

Jika saya melakukan submit pada formulir yang textbox ini ditempatkan di validasi akan dilakukan pertama pada klien dan kemudian pada service ( ModelState.IsValid).

Sekarang saya punya beberapa pertanyaan:

  1. Bisakah ini digunakan dengan jQuery ajax submit? Apa yang saya lakukan hanyalah menghapus formulir dan mengklik tombol kirim, javascript akan mengumpulkan data dan kemudian menjalankan $.ajax.

  2. Akankah sisi server ModelState.IsValidberfungsi?

  3. Bagaimana saya bisa meneruskan masalah validasi kembali ke klien dan menampilkannya seolah-olah saya menggunakan build int validation ( @Html.ValidationSummary(true))?

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

Edit 1:

Disertakan di halaman:

<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>
Ivy
sumber
Jawaban bagus di bawah. Berikut pertanyaan terkait. Jawabannya memungkinkan validasi sisi klien atau sisi server. Saya jatuh cinta dengan kode JQuery yang mereka sediakan. (Tidak, itu bukan jawaban saya.) Stackoverflow.com/questions/28987752/…
Petualangan

Jawaban:

155

Sisi klien

Menggunakan jQuery.validatepustaka seharusnya cukup sederhana untuk disiapkan.

Tentukan pengaturan berikut di Web.configfile Anda :

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

Saat Anda membangun tampilan, Anda akan mendefinisikan hal-hal seperti ini:

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

CATATAN: Ini perlu didefinisikan dalam elemen formulir

Maka Anda perlu menyertakan pustaka berikut:

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

Ini seharusnya dapat menyiapkan Anda untuk validasi sisi klien

Sumber daya

Sisi server

CATATAN: Ini hanya untuk validasi sisi server tambahan di atas jQuery.validationperpustakaan

Mungkin sesuatu seperti ini bisa membantu:

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

Dimana ValidateAjaxatribut didefinisikan sebagai:

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

Apa yang dilakukannya adalah mengembalikan objek JSON yang menentukan semua kesalahan model Anda.

Contoh tanggapannya adalah

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

Ini akan dikembalikan ke kesalahan Anda saat menangani panggilan balik dari $.ajaxpanggilan tersebut

Anda dapat melakukan perulangan melalui data yang dikembalikan untuk mengatur pesan kesalahan sesuai kebutuhan berdasarkan Kunci yang dikembalikan (saya pikir sesuatu seperti $('input[name="' + err.key + '"]')akan menemukan elemen input Anda

Andrew Burgess
sumber
1
Jawaban yang bagus, terutama dengan ValidateAjaxAttribute yang luar biasa! Terima kasih!
René
3
Saya tidak mengerti mengapa jawaban ini mendapat begitu banyak suara. Itu tidak menjawab pertanyaan 1: bagaimana melakukan validasi klien saat memposting dengan $ .ajax? Saya pikir jawaban @Shyju membantu dengan itu.
Valentin
2
@Valentin - jawaban saya memang membantu karena datanya juga divalidasi di sisi server. Plugin validasi harus mengaktifkan validasi dinamis saat formulir diisi, dan saat formulir dikirimkan (namun OP ingin melakukannya), server akan memberikan validasi akhir, yang lebih disukai karena validasi sisi klien dapat dilewati.
Andrew Burgess
8
Saya menggunakan rentang pesan validasi jQuery dengan mengulang melalui kesalahan yang dikembalikan dan memasukkan pesan kesalahan ke dalam rentang yang benar:for (var i = 0; i < modelStateErrors.length; i++) { $('span[data-valmsg-for="' + modelStateErrors[i].key + '"]').text(modelStateErrors[i].errors[0]); }
Ian
7
Jawaban ini bagus! Tapi saya masih berpikir kerangka ASP.NET MVC harus menyediakan cara built-in untuk melakukan itu.
Zignd
40

Apa yang harus Anda lakukan adalah membuat data formulir Anda dan mengirimkannya ke tindakan pengontrol. ASP.NET MVC akan mengikat data formulir ke EditPostViewModelobjek (parameter metode tindakan Anda), menggunakan fitur pengikatan model MVC.

Anda dapat memvalidasi formulir Anda di sisi klien dan jika semuanya baik-baik saja, kirim data ke server. The valid()Metode akan berguna.

$(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
sumber
1
Terima kasih! Saya mencoba ini $ ("form #" + formId) .validate () tetapi dikatakan bahwa formulir (yang ditemukan) tidak memiliki validate ()?
Ivy
Lihat Edit1 di mana saya menunjukkan bahwa skrip validasi disertakan di halaman web. Saya juga melihat bahwa validasi berjalan saat menggunakan tombol kirim jenis masukan biasa.
Ivy
Saya menemukan masalah (menghapus Scripts.Render dari halaman master). Tetapi masih memiliki masalah untuk mengirim kembali kesalahan validasi ModelState ke klien? Bagaimana saya bisa mengatasi itu? Misalnya jika pengguna tidak masuk lagi (ModelState.AddModelError ("CustomError", "validation text").
Ivy
1
Anda perlu menyertakan file jquery.validate dan jquery.validate.unobtrusive js di halaman Anda. APAKAH input HTML Anda memiliki atribut yang dicari plugin validasi?
Shyju
1
Ivy: Jenis pengembalian Anda (ActionResult) adalah kelas dasar JsonResult. sehingga dapat mengembalikan data JSON. Apa yang harus Anda lakukan adalah, Jika itu adalah panggilan ajax (periksa Request.IsAjax), dapatkan kesalahan validasi dan buat JSON dan kirimkan kembali ke klien. Periksa json dalam metode callback $ .post dan tunjukkan pesan kesalahan.
Shyju
9

Berikut solusi yang agak sederhana:

Di pengontrol kami mengembalikan kesalahan kami seperti ini:

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

Berikut beberapa skrip klien:

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

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

Begitulah cara kami menanganinya melalui 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);
        }
    }
});

Juga, saya membuat tampilan parsial melalui ajax dengan cara berikut:

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

Metode 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();
        }
    }
Alex Herman
sumber
3
"GetModelStateErrors" Anda dapat disederhanakan sepenuhnya dengan mengubahnya menjadi pernyataan baris tunggal yang lebih sederhana: return ModelState.Values.SelectMany (x => x.Errors) .Select (x => x.ErrorMessage) .ToList ();
Camilo Terevinto
1
Mengapa tidak mengembalikan saja PartialViewke Ajax?
Sinjai
4

Menambahkan beberapa logika lagi ke solusi yang disediakan oleh @Andrew Burgess. Inilah solusi lengkapnya:

Membuat filter tindakan untuk mendapatkan kesalahan untuk permintaan 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;
            }
        }
    }

Menambahkan filter ke metode pengontrol saya sebagai:

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

Menambahkan skrip umum untuk validasi 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);
}

Akhirnya menambahkan metode javascript kesalahan ke formulir Ajax Begin saya:

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

Anda bisa melakukannya dengan cara ini:

( Sunting: Menimbang bahwa Anda sedang menunggu tanggapan jsondengan dataType: 'json')

.BERSIH

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

Jika perlu, saya juga bisa menjelaskan cara melakukannya dengan mengembalikan error 500, dan mendapatkan error di acara error (ajax). Tetapi dalam kasus Anda, ini mungkin menjadi pilihan

andres descalzo
sumber
1
Saya tahu bagaimana melakukan permintaan Jason biasa, namun ini tidak akan membantu saya dengan validasi properti yang berbeda atau bahkan menggunakan Validasi MVC ASP.NET bawaan yang saya minta. Saya mungkin bisa membangun objek Jason yang rumit untuk menjelaskan kesalahan validasi untuk setiap properti tetapi ini akan banyak pekerjaan dan saya berharap Anda dapat menggunakan kembali fungsi built-in dari validasi ASP.NET MVC untuk ini?
Ivy
1 - Bagaimana menjalankan fungsi "SendPost" Anda ?, Dan 2 - data valid Anda pada klien?
andres descalzo
Mohon jelaskan? Tidak mendapatkan postingan terakhir Anda?
Ivy