Menggunakan Ajax.BeginForm dengan ASP.NET MVC 3 Razor

264

Apakah ada tutorial atau kode contoh penggunaan Ajax.BeginFormdalam Asp.net MVC 3 di mana validasi dan Ajax tidak mengganggu?

Ini adalah topik yang sulit dipahami untuk MVC 3, dan sepertinya saya tidak bisa mendapatkan formulir saya untuk berfungsi dengan baik. Ini akan melakukan pengiriman Ajax tetapi mengabaikan kesalahan validasi.

JBeckton
sumber

Jawaban:

427

Contoh:

Model:

public class MyViewModel
{
    [Required]
    public string Foo { get; set; }
}

Pengendali:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        return View(new MyViewModel());
    }

    [HttpPost]
    public ActionResult Index(MyViewModel model)
    {
        return Content("Thanks", "text/html");
    }
}

Melihat:

@model AppName.Models.MyViewModel

<script src="@Url.Content("~/Scripts/jquery.unobtrusive-ajax.js")" type="text/javascript"></script>
<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>

<div id="result"></div>

@using (Ajax.BeginForm(new AjaxOptions { UpdateTargetId = "result" }))
{
    @Html.EditorFor(x => x.Foo)
    @Html.ValidationMessageFor(x => x.Foo)
    <input type="submit" value="OK" />
}

dan inilah contoh yang lebih baik (dalam perspektif saya):

Melihat:

@model AppName.Models.MyViewModel

<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>
<script src="@Url.Content("~/Scripts/index.js")" type="text/javascript"></script>

<div id="result"></div>

@using (Html.BeginForm())
{
    @Html.EditorFor(x => x.Foo)
    @Html.ValidationMessageFor(x => x.Foo)
    <input type="submit" value="OK" />
}

index.js:

$(function () {
    $('form').submit(function () {
        if ($(this).valid()) {
            $.ajax({
                url: this.action,
                type: this.method,
                data: $(this).serialize(),
                success: function (result) {
                    $('#result').html(result);
                }
            });
        }
        return false;
    });
});

yang dapat lebih ditingkatkan dengan plugin formulir jQuery .

Darin Dimitrov
sumber
41
Saya setuju tentang menggunakan jQUery untuk Ajax. Saya pikir sebagian besar aplikasi Asp.net MVC Ajax bukan menggunakan jQuery daripada ekstensi Ajax bawaan.
Robert Koritnik
6
Saya menggunakan sesuatu seperti berikut ini dan hasilnya tampaknya pergi ke halaman sendiri dan bukan hanya mengganti hasil div. Apa kamu tahu kenapa?
David
3
Ya, saya setuju juga dalam menggunakan jQuery murni untuk ajax, menggunakan ekstensi MVC ajax berarti Anda tidak perlu mempelajari aturan lain dan sintaks untuk, pada akhirnya, menggunakan jQuery. Jadi bahkan saya perlu menulis lebih banyak, tetapi lebih baik melakukannya dengan cara yang benar, ditambah Anda mendapatkan lebih banyak kontrol dan fleksibilitas.
Nestor
3
@ darin-dimitrov: ketika saya mencoba contoh terakhir Anda, saya harus menambahkan data: $ ('form'). serialize (), ke panggilan ajax (). Jika tidak, tidak ada data formulir yang diteruskan dan model saya tidak valid di sisi server. Bertanya-tanya apakah ada sesuatu yang saya abaikan?
Brett
2
@DarinDimitrov bagaimana jika ada kesalahan dengan BLL dan Anda harus mengirim model kembali ke Lihat dan menampilkan pesan kesalahan karena lapisan yang mengeras memberikan validasi yang lebih dalam pada data dan menemukan masalah. Hanya mengandalkan validasi sisi Klien saja tidak cukup. Anda tidak dapat mengembalikan tampilan (model); sekarang karena seluruh tampilan di-render dalam hasil div ... apa solusinya?
CD Smith
54

Saya pikir semua jawaban melewatkan satu poin penting:

Jika Anda menggunakan formulir Ajax sehingga perlu memperbarui sendiri (dan BUKAN div lain di luar formulir) maka Anda harus meletakkan div berisi di luar formulir. Sebagai contoh:

 <div id="target">
 @using (Ajax.BeginForm("MyAction", "MyController",
            new AjaxOptions
            {
                HttpMethod = "POST",
                InsertionMode = InsertionMode.Replace,
                UpdateTargetId = "target"
            }))
 {
      <!-- whatever -->
 }
 </div>

Kalau tidak, Anda akan berakhir seperti @David tempat hasilnya ditampilkan di halaman baru.

Dror
sumber
7
Masalah David hampir selalu disebabkan dari tidak termasuk bundel jqueryval yang berisi kode ajax tidak mencolok. Berhati-hatilah dengan pendekatan yang Anda posting ini jika tidak, Anda akan mendapatkan satu posting dan kemudian formulir Anda disembunyikan karena Anda baru saja menggantinya. Anda kemudian memerlukan tampilan "MyAction" Anda untuk mengelola formulirnya dan menentukan kembali semua opsi ajax di dalamnya.
Adam Tuliper - MSFT
Dalam aplikasi saya, targetkan div yang menampilkan seluruh formulir dengan halaman master, tolong bantu saya
Nitin ...
Bagi saya, saya belum menetapkan UnobtrusiveJavaScriptEnabledke mana pun
Kunal
15

Saya mendapatkan solusi Darwin yang akhirnya berhasil tetapi membuat beberapa kesalahan terlebih dahulu yang menghasilkan masalah yang mirip dengan David (dalam komentar di bawah solusi Darwin) di mana hasilnya diposting ke halaman baru.

Karena saya harus melakukan sesuatu dengan formulir setelah metode kembali, saya menyimpannya untuk digunakan nanti:

var form = $(this);

Namun, variabel ini tidak memiliki properti "action" atau "method" yang digunakan dalam panggilan ajax.

$(document).on("submit", "form", function (event) {
    var form = $(this);

    if (form.valid()) {
        $.ajax({
            url: form.action, // Not available to 'form' variable
            type: form.method,  // Not available to 'form' variable
            data: form.serialize(),
            success: function (html) {
                // Do something with the returned html.
            }
        });
    }

    event.preventDefault();
});

Alih-alih, Anda perlu menggunakan variabel "ini":

$.ajax({
    url: this.action, 
    type: this.method,
    data: $(this).serialize(),
    success: function (html) {
        // Do something with the returned html.
    }
});
Jason
sumber
5
Itu karena variabel bentuk Anda telah menetapkan jQueryobjek dengan formulir sebagai pemilih. form[0]akan memiliki sifat. Ini juga praktik yang baik untuk mengawali setiap jQueryvariabel dengan $agar lebih mudah mengidentifikasi mereka.
James South
6

Solusi Darin Dimitrov bekerja untuk saya dengan satu pengecualian. Ketika saya mengirimkan tampilan sebagian dengan kesalahan validasi (disengaja), saya berakhir dengan formulir duplikat yang dikembalikan dalam dialog:

masukkan deskripsi gambar di sini

Untuk memperbaikinya saya harus membungkus Html.BeginForm dalam div:

<div id="myForm">
    @using (Html.BeginForm("CreateDialog", "SupportClass1", FormMethod.Post, new { @class = "form-horizontal" }))
    {
        //form contents
    }
</div>

Ketika formulir dikirimkan, saya membersihkan div di fungsi keberhasilan dan menampilkan formulir yang divalidasi:

    $('form').submit(function () {
        if ($(this).valid()) {
            $.ajax({
                url: this.action,
                type: this.method,
                data: $(this).serialize(),
                success: function (result) {
                    $('#myForm').html('');
                    $('#result').html(result);
                }
            });
        }
        return false;
    });
});
steveareeno
sumber
Saya juga mendapatkan kesalahan yang sama. Saya menggunakan Partial Viewsuntuk membuat fungsi create di bawah halaman indeks. Saya bisa mendapatkan semua pesan validasi di Tampilan parsial. Tetapi ketika Createberhasil, indeks ditampilkan dua kali. Saya tidak punya Html.BeginFormdalam Tampilan Indeks saya.
Vini
Coba gunakan UpdateTargetId = "myForm"sebagai gantinya
Kunal
4

Jika tidak ada validasi data yang dikecualikan, atau konten selalu dikembalikan di jendela baru, pastikan 3 baris ini ada di bagian atas tampilan:

<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.unobtrusive-ajax.min.js")" type="text/javascript"></script>
cheny
sumber
Saya tidak menemukan mereka dalam solusi. Saya harus menginstalnya dari manajer paket
Nuget
3

Contoh

// Dalam Model

public class MyModel
{  
   [Required]
    public string Name{ get; set; }
}

// Di PartailView //PartailView.cshtml

@model MyModel

<div>
    <div>
      @Html.LabelFor(model=>model.Name)
    </div>
    <div>
        @Html.EditorFor(model=>model.Name)
        @Html.ValidationMessageFor(model => model.Name)
    </div>
</div>

Dalam tampilan Index.cshtml

@model MyModel
<div id="targetId">
    @{Html.RenderPartial("PartialView",Model)}
</div>

@using(Ajax.BeginForm("AddName", new AjaxOptions { UpdateTargetId = "targetId", HttpMethod = "Post" }))
{
     <div>
        <input type="submit" value="Add Unit" />
    </div>
}

Di Kontroler

public ActionResult Index()
{
  return View(new MyModel());
}


public string AddName(MyModel model)
{
   string HtmlString = RenderPartialViewToString("PartailView",model);
   return HtmlString;
}


protected string RenderPartialViewToString(string viewName, object model)
        {
            if (string.IsNullOrEmpty(viewName))
                viewName = ControllerContext.RouteData.GetRequiredString("action");

            ViewData.Model = model;

            using (StringWriter sw = new StringWriter())
            {
                ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(ControllerContext, viewName);
                ViewContext viewContext = new ViewContext(ControllerContext, viewResult.View, ViewData, TempData, sw);
                viewResult.View.Render(viewContext, sw);
                return sw.GetStringBuilder().ToString();
            }
        }

Anda harus melewati ViewName dan Model ke metode RenderPartialViewToString. itu akan mengembalikan tampilan Anda dengan validasi yang Anda terapkan dalam model dan menambahkan konten di div "targetId" di Index.cshtml. Saya dengan cara ini dengan menangkap RenderHtml dari tampilan parsial Anda dapat menerapkan validasi.

Shivkumar
sumber
3

Bentuk Ajax bekerja secara asinkron menggunakan Javascript. Jadi diperlukan, untuk memuat file skrip untuk dieksekusi. Meskipun ini adalah kompromi kinerja yang kecil, eksekusi terjadi tanpa pos balik.

Kita perlu memahami perbedaan antara perilaku kedua bentuk Html dan Ajax.

Ajax:

  1. Tidak akan mengarahkan ulang formulir, bahkan Anda melakukan RedirectAction ().

  2. Akan melakukan simpan, perbarui, dan operasi modifikasi apa pun secara serempak.

Html:

  1. Akan mengarahkan ulang formulir.

  2. Akan melakukan operasi baik secara Sinkron dan Asinkron (Dengan beberapa kode dan perawatan tambahan).

Menunjukkan perbedaan dengan POC di tautan di bawah ini. Tautan

pengguna1080810
sumber
1

Sebelum menambahkan Ajax.BeginForm. Tambahkan skrip di bawah ini ke proyek Anda dalam urutan yang disebutkan,

  1. jquery-1.7.1.min.js
  2. jquery.unobtrusive-ajax.min.js

Hanya dua ini yang cukup untuk melakukan operasi Ajax.

Balaji Dinakaran
sumber