Bagaimana cara mendapatkan respons ASP.NET MVC Ajax untuk mengalihkan ke halaman baru alih-alih memasukkan tampilan ke UpdateTargetId?


88

Saya menggunakan Ajax.BeginForm untuk membuat formulir yang akan melakukan postback ajax ke tindakan pengontrol tertentu dan kemudian jika tindakan berhasil, pengguna harus dialihkan ke halaman lain (jika tindakan gagal maka pesan status ditampilkan menggunakan AjaxOptions UpdateTargetId).

using (Ajax.BeginForm("Delete", null,
        new { userId = Model.UserId },
        new AjaxOptions { UpdateTargetId = "UserForm", LoadingElementId = "DeletingDiv" },
        new { name = "DeleteForm", id = "DeleteForm" }))
   {
    [HTML DELETE BUTTON]
   }

Jika penghapusan berhasil, saya mengembalikan hasil Redirect:

[Authorize]
public ActionResult Delete(Int32 UserId)
{
    UserRepository.DeleteUser(UserId);
    return Redirect(Url.Action("Index", "Home"));
}

Tapi tampilan Home Controller Index dimuat ke UpdateTargetId dan oleh karena itu saya berakhir dengan sebuah halaman di dalam sebuah halaman. Dua hal yang saya pikirkan:

  1. Entah saya merancang ini salah dan harus menangani jenis tindakan ini secara berbeda (tidak menggunakan ajax).
  2. Alih-alih mengembalikan hasil Pengalihan, kembalikan tampilan yang memiliki javascript di dalamnya yang melakukan pengalihan di sisi klien.

Apakah ada yang punya komentar di # 1? Atau jika # 2 adalah solusi yang baik, seperti apa tampilan "redirect javascript"?

Jawaban:


171

Anda dapat menggunakan JavascriptResultuntuk mencapai ini.

Untuk mengalihkan:

return JavaScript("window.location = 'http://www.google.co.uk'");

Untuk memuat ulang halaman saat ini:

return JavaScript("location.reload(true)");

Sepertinya opsi paling sederhana.


4
Luar biasa .. Membantu saya.
CrazyCoderz

1
Saya setuju, ini adalah pendekatan yang tepat. Jawaban stackoverflow.com/a/2841608/498969 ini menunjukkan bagaimana Anda dapat menerapkan fungsionalitas ini secara default menggunakan pengontrol dasar.
Adam Spicer

@Ben Foster: Menggunakan penelusuran ini mencoba membuka url http :: window.location ... Saya memposting ini sebagai pertanyaan terpisah di stackoverflow.com/questions/13896307/…
Andrus

30
Jika Anda ingin mengalihkan ke pengontrol dalam proyek Anda, Anda dapat menggunakan helper Url untuk Anda. Misalnya:return JavaScript( "window.location = '" + Url.Action("Edit","Dispatch") + "'" );
Chris Morgan

2
Pendek. Sederhana. Luar biasa. Bagus!
Vikram

30

Anda dapat mengembalikan JSON dengan URL dan mengubah lokasi window.location menggunakan JavaScript di sisi klien. Saya lebih suka cara ini daripada memanggil fungsi JavaScript dari server, yang menurut saya itu melanggar pemisahan masalah.

Sisi server:

return Json(new {result = "Redirect", url = Url.Action("ActionName", "ControllerName")});

Sisi klien:

if (response.result == 'Redirect')
    window.location = response.url;

Tentu saja Anda dapat menambahkan lebih banyak logika karena mungkin ada kesalahan di sisi server dan dalam hal ini properti hasil dapat menunjukkan situasi ini dan menghindari pengalihan.


12

Perilaku yang Anda coba hasilkan tidak paling baik dilakukan menggunakan AJAX. AJAX paling baik digunakan jika Anda hanya ingin memperbarui sebagian halaman, tidak sepenuhnya mengalihkan ke halaman lain. Itu benar-benar mengalahkan seluruh tujuan AJAX.

Saya menyarankan untuk tidak menggunakan AJAX dengan perilaku yang Anda gambarkan.

Alternatifnya, Anda bisa mencoba menggunakan jquery Ajax, yang akan mengirimkan permintaan dan kemudian Anda menentukan callback saat permintaan selesai. Dalam callback, Anda dapat menentukan apakah gagal atau berhasil, dan mengarahkan ke halaman lain jika berhasil. Saya telah menemukan jquery Ajax jauh lebih mudah digunakan, terutama karena saya sudah menggunakan perpustakaan untuk hal-hal lain.

Anda dapat menemukan dokumentasi tentang jquery ajax di sini , tetapi sintaksnya adalah sebagai berikut:

jQuery.ajax( options )  

jQuery.get( url, data, callback, type)

jQuery.getJSON( url, data, callback )

jQuery.getScript( url, callback )

jQuery.post( url, data, callback, type)

Jadi lakukan saja POST biasa ke tindakan Hapus dan dalam banyak kasus itu akan berhasil dan kemudian saya bisa mengarahkan ke halaman Indeks Beranda. Dalam kasus di mana itu akan gagal, maka tampilkan tampilan yang berbeda dengan pesan kesalahan dan tindakan yang sesuai untuk diambil pengguna. Kedengarannya oke?
Jeff Widmer

Ya sepertinya itu akan lebih masuk akal.
Joseph

Saya melanjutkan dengan mengubah ini dari pengiriman Ajax ke POST biasa sesuai rekomendasi Joseph. Ini sebenarnya bekerja lebih baik karena memberi saya cara yang lebih bersih untuk menangani pesan konfirmasi penghapusan.
Jeff Widmer

12

Meskipun tidak elegan, tetapi cocok untuk saya dalam situasi tertentu.

Kontroler

if (RedirectToPage)
    return PartialView("JavascriptRedirect", new JavascriptRedirectModel("http://www.google.com"));
else
   ... return regular ajax partialview

Model

    public JavascriptRedirectModel(string location)
    {
        Location = location;
    }

    public string Location { get; set; }

/Views/Shared/JavascriptRedirect.cshtml

@model Models.Shared.JavascriptRedirectModel

<script type="text/javascript">
    window.location = '@Model.Location';
</script>

2
Kenapa tidak elegan? Ini diketik dengan kuat, dan terasa jelas. Saya suka pendekatan itu. +1
T-moty

6

Menggunakan JavaScriptpasti akan melakukan pekerjaan itu.

Anda juga dapat menggunakan Contentjika ini lebih sesuai gaya Anda.

Contoh:

Pengontrol MVC

[HttpPost]
public ActionResult AjaxMethod()
{
    return Content(@"http://www.google.co.uk");
}

Javascript

$.ajax({
    type: 'POST',
    url: '/AjaxMethod',
    success: function (redirect) {
        window.location = redirect;
    }
});

Terima kasih! Ini sangat membantu saya.
dee

5

Anda cukup menulis di Ajax Success seperti di bawah ini:

 $.ajax({
            type: "POST",
            url: '@Url.Action("GetUserList", "User")',
            data: { id: $("#UID").val() },
            success: function (data) {
                window.location.href = '@Url.Action("Dashboard", "User")';
            },
            error: function () {
                $("#loader").fadeOut("slow");
            }
});

2

Bagaimana dengan ini :

public ActionResult GetGrid()
{
   string url = "login.html";
   return new HttpStatusCodeResult(System.Net.HttpStatusCode.Redirect,url)
}

Lalu

$(document).ajaxError(function (event, jqxhr, settings, thrownError) { 
   if (jqxhr.status == 302) {
      location.href = jqxhr.statusText;
   }           
});

Atau

error: function (a, b, c) {
       if (a.status == 302) {
         location.href = a.statusText;
       }  
}

1

Saya perlu melakukan ini karena saya memiliki formulir login ajax. Ketika pengguna berhasil masuk, saya mengarahkan ke halaman baru dan mengakhiri permintaan sebelumnya karena halaman lain menangani pengalihan kembali ke pihak mengandalkan (karena ini adalah Sistem STS SSO).

Namun, saya juga ingin itu bekerja dengan javascript dinonaktifkan, menjadi pusat login hop dan sebagainya, jadi saya datang dengan ini,

    public static string EnsureUrlEndsWithSlash(string url)
    {
        if (string.IsNullOrEmpty(url))
            throw new ArgumentNullException("url");
        if (!url.EndsWith("/"))
            return string.Concat(url, "/");
        return url;
    }

    public static string GetQueryStringFromArray(KeyValuePair<string, string>[] values)
    {
        Dictionary<string, string> dValues = new Dictionary<string,string>();
        foreach(var pair in values)            
            dValues.Add(pair.Key, pair.Value);            
        var array = (from key in dValues.Keys select string.Format("{0}={1}", HttpUtility.UrlEncode(key), HttpUtility.UrlEncode(dValues[key]))).ToArray();
        return "?" + string.Join("&", array);
    }

    public static void RedirectTo(this HttpRequestBase request, string url, params KeyValuePair<string, string>[] queryParameters)
    {            
        string redirectUrl = string.Concat(EnsureUrlEndsWithSlash(url), GetQueryStringFromArray(queryParameters));
        if (request.IsAjaxRequest())
            HttpContext.Current.Response.Write(string.Format("<script type=\"text/javascript\">window.location='{0}';</script>", redirectUrl));
        else
            HttpContext.Current.Response.Redirect(redirectUrl, true);

    }

1

Anda cukup melakukan beberapa jenis filter respons ajax untuk respons masuk dengan $ .ajaxSetup . Jika respons berisi pengalihan MVC, Anda dapat mengevaluasi ekspresi ini di sisi JS. Contoh kode untuk JS di bawah ini:

$.ajaxSetup({
    dataFilter: function (data, type) {
        if (data && typeof data == "string") {
            if (data.indexOf('window.location') > -1) {
                eval(data);
            }
        }
        return data;
    }
});

Jika data adalah: "window.location = '/ Acount / Login'" di atas filter akan menangkapnya dan mengevaluasi untuk membuat pengalihan.


0

Saya tidak puas dengan jawaban terbaik dari Joseph, alih-alih memperbaiki masalah yang benar, dia mengatakan bahwa ini kasus penggunaan yang salah. Sebenarnya ada banyak tempat misalnya jika Anda mengonversi basis kode lama menjadi kode ajaxified dan di sana Anda MEMBUTUHKANnya, maka Anda MEMBUTUHKANnya. Dalam pemrograman tidak ada alasan karena tidak hanya Anda yang mengkodekan semua pengembang yang buruk dan baik dan Anda harus bekerja berdampingan. Jadi jika saya tidak melakukan pengalihan kode di ajax, rekan pengembang saya dapat memaksa saya untuk memiliki solusi untuk itu. Sama seperti saya suka menggunakan semua situs berpola AMD atau mvc4, dan perusahaan saya dapat menjauhkan saya darinya selama setahun.

Jadi mari kita bicarakan solusinya sekarang.

Saya telah melakukan permintaan ajax dan penanganan respons dan cara paling sederhana yang saya temukan adalah mengirim kode status ke klien dan memiliki satu fungsi javascript standar untuk memahami kode-kode itu. Jika saya hanya mengirim misalnya kode 13 itu mungkin berarti pengalihan.

Jadi respon json seperti {statusCode: 13, messsage: '/ home / logs-in'} tentu saja ada banyak variasi yang diusulkan seperti {status: 'success', code: 13, url: '/ home / logs-in ', pesan:' Anda masuk sekarang '}

dll, jadi terserah pilihan pesan standar Anda sendiri

Biasanya saya Mewarisi dari kelas Pengontrol dasar dan memberikan pilihan tanggapan standar saya seperti ini

public JsonResult JsonDataResult(object data, string optionalMessage = "")
    {
        return Json(new { data = data, status = "success", message = optionalMessage }, JsonRequestBehavior.AllowGet);
    }

    public JsonResult JsonSuccessResult(string message)
    {
        return Json(new { data = "", status = "success", message = message }, JsonRequestBehavior.AllowGet);
    }

    public JsonResult JsonErrorResult(string message)
    {
        return Json(new { data = "", status = "error", message = message }, JsonRequestBehavior.AllowGet);
    }

    public JsonResult JsonRawResult(object data)
    {
        return Json(data, JsonRequestBehavior.AllowGet);
    }

Tentang menggunakan $ .ajax sebagai pengganti Ajax.BeginForm Saya ingin menggunakan Jquery ajax dan saya melakukannya, tetapi sekali lagi bukan saya di seluruh dunia untuk membuat keputusan, saya memiliki aplikasi penuh dengan Ajax.BeginForm dan tentu saja saya tidak melakukan itu. Tapi saya harus menerimanya.

Jadi Ada callback sukses dalam bentuk begin juga, Anda tidak perlu menggunakan jquery ajax untuk menggunakan callback. Sesuatu tentang itu di sini Ajax.BeginForm, Calls Action, Returns JSON, Bagaimana cara mengakses objek JSON di Fungsi JS OnSuccess saya?

Terima kasih


0

Jika Anda dialihkan dari kelas JavaScript

pandangan yang sama - pengontrol yang berbeda

<strike>window.location.href = `'Home'`;</strike>

bukan pandangan yang sama

<strike>window.location.href = `'Index/Home'`;</strike>

0

Tambahkan kelas pembantu:

public static class Redirector {
        public static void RedirectTo(this Controller ct, string action) {
            UrlHelper urlHelper = new UrlHelper(ct.ControllerContext.RequestContext);

            ct.Response.Headers.Add("AjaxRedirectURL", urlHelper.Action(action));
        }

        public static void RedirectTo(this Controller ct, string action, string controller) {
            UrlHelper urlHelper = new UrlHelper(ct.ControllerContext.RequestContext);

            ct.Response.Headers.Add("AjaxRedirectURL", urlHelper.Action(action, controller));
        }

        public static void RedirectTo(this Controller ct, string action, string controller, object routeValues) {
            UrlHelper urlHelper = new UrlHelper(ct.ControllerContext.RequestContext);

            ct.Response.Headers.Add("AjaxRedirectURL", urlHelper.Action(action, controller, routeValues));
        }
    }

Kemudian serukan tindakan Anda:

this.RedirectTo ("Indeks", "Semen");

Tambahkan kode javascript ke file yang disertakan javascript global atau file tata letak untuk mencegat semua permintaan ajax:

<script type="text/javascript">
  $(function() {
    $(document).ajaxComplete(function (event, xhr, settings) {
            var urlHeader = xhr.getResponseHeader('AjaxRedirectURL');

            if (urlHeader != null && urlHeader !== undefined) {
                window.location = xhr.getResponseHeader('AjaxRedirectURL');
            }
        });
  });
</script>


0

Seperti yang dikatakan ben foster, Anda dapat mengembalikan Javascripts dan itu akan mengarahkan Anda ke halaman yang diinginkan.

Untuk memuat halaman di halaman saat ini:

return JavaScript("window.location = 'http://www.google.co.uk'");'

Untuk memuat halaman di tab baru:

return JavaScript("window.open('http://www.google.co.uk')");

0

Anda bisa mendapatkan pengalihan berbasis non-js dari panggilan ajax dengan memasukkan salah satu tag meta refresh tersebut. Ini di sini sepertinya berhasil: return Content("<meta http-equiv=\"refresh\" content=\"0;URL='" + @Url.Action("Index", "Home") + "'\" />");

Catatan: Saya menemukan bahwa meta refresh dinonaktifkan secara otomatis oleh Firefox, membuat ini tidak terlalu berguna.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.