วิธีรับการตอบสนอง ASP.NET MVC Ajax เพื่อเปลี่ยนเส้นทางไปยังหน้าใหม่แทนที่จะแทรกมุมมองลงใน UpdateTargetId


88

ฉันใช้ Ajax BeginForm เพื่อสร้างแบบฟอร์มซึ่งจะทำการโพสต์แบ็คของ ajax ไปยังแอ็คชันคอนโทรลเลอร์บางอย่างจากนั้นหากการดำเนินการสำเร็จผู้ใช้ควรได้รับการเปลี่ยนเส้นทางไปยังเพจอื่น (หากการดำเนินการล้มเหลวข้อความสถานะจะแสดงโดยใช้ 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]
   }

หากการลบสำเร็จฉันจะส่งคืนผลลัพธ์การเปลี่ยนเส้นทาง:

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

แต่มุมมอง Home Controller Index กำลังโหลดลงใน UpdateTargetId ดังนั้นฉันจึงจบลงด้วยหน้าภายในหนึ่งหน้า สองสิ่งที่ฉันคิดเกี่ยวกับ:

  1. ฉันกำลังออกแบบสิ่งนี้ผิดและควรจัดการการกระทำประเภทนี้แตกต่างกัน (ไม่ใช้ ajax)
  2. แทนที่จะส่งคืนผลลัพธ์การเปลี่ยนเส้นทางให้ส่งคืนมุมมองที่มีจาวาสคริปต์อยู่ในนั้นซึ่งทำการเปลี่ยนเส้นทางในฝั่งไคลเอ็นต์

ใครมีความคิดเห็นเกี่ยวกับ # 1? หรือถ้า # 2 เป็นทางออกที่ดี "redirect javascript view" จะเป็นอย่างไร

คำตอบ:


171

คุณสามารถใช้JavascriptResultเพื่อบรรลุสิ่งนี้

ในการเปลี่ยนเส้นทาง:

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

ในการโหลดหน้าปัจจุบันซ้ำ:

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

ดูเหมือนจะเป็นตัวเลือกที่ง่ายที่สุด


1
ฉันเห็นด้วยนี่เป็นแนวทางที่ถูกต้อง คำตอบนี้stackoverflow.com/a/2841608/498969แสดงวิธีที่คุณสามารถใช้ฟังก์ชันนี้โดยค่าเริ่มต้นโดยใช้ตัวควบคุมพื้นฐาน
Adam Spicer

@ เบ็นฟอสเตอร์: การใช้เบราส์นี้พยายามเปิด url http :: window.location ... ฉันโพสต์เป็นคำถามแยกต่างหากในstackoverflow.com/questions/13896307/…
Andrus

30
หากคุณต้องการเปลี่ยนเส้นทางไปยังคอนโทรลเลอร์ในโปรเจ็กต์ของคุณคุณสามารถใช้ตัวช่วย URL สำหรับคุณได้ ตัวอย่างเช่น:return JavaScript( "window.location = '" + Url.Action("Edit","Dispatch") + "'" );
Chris Morgan

นี่ทำให้ฉันอยากจะร้องไห้ การผสมผสานระหว่างแนวคิดและแนวคิดตัวควบคุมพื้นฐานนั้นยอดเยี่ยม
secretwep

30

คุณสามารถส่งคืน JSON พร้อม URL และเปลี่ยน window.location โดยใช้ JavaScript ที่ฝั่งไคลเอ็นต์ ฉันชอบวิธีนี้มากกว่าการเรียกใช้ฟังก์ชัน JavaScript จากเซิร์ฟเวอร์ซึ่งฉันคิดว่ามันทำลายข้อกังวลที่แยกออกจากกัน

ฝั่งเซิร์ฟเวอร์:

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

ด้านลูกค้า:

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

แน่นอนคุณสามารถเพิ่มตรรกะได้มากขึ้นเนื่องจากอาจมีข้อผิดพลาดที่ฝั่งเซิร์ฟเวอร์และในกรณีนั้นคุณสมบัติผลลัพธ์อาจบ่งชี้สถานการณ์นี้และหลีกเลี่ยงการเปลี่ยนเส้นทาง


13

แม้ว่าจะไม่สวยหรู แต่ก็เหมาะกับฉันในบางสถานการณ์

ตัวควบคุม

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

รุ่น

    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
ทำไมไม่สง่างาม? พิมพ์ผิดมากและให้ความรู้สึกชัดเจน ฉันชอบแนวทางนั้น +1
T-moty

12

พฤติกรรมที่คุณพยายามสร้างขึ้นนั้นไม่สามารถทำได้ดีที่สุดเมื่อใช้ AJAX AJAX จะใช้งานได้ดีที่สุดหากคุณต้องการอัปเดตเฉพาะบางส่วนของเพจโดยไม่เปลี่ยนเส้นทางไปยังเพจอื่นอย่างสมบูรณ์ นั่นเป็นการเอาชนะจุดประสงค์ทั้งหมดของ AJAX จริงๆ

ฉันขอแนะนำว่าอย่าใช้ AJAX กับพฤติกรรมที่คุณกำลังอธิบาย

หรือคุณสามารถลองใช้ jquery Ajax ซึ่งจะส่งคำขอจากนั้นระบุการติดต่อกลับเมื่อคำขอเสร็จสมบูรณ์ ในการติดต่อกลับคุณสามารถระบุได้ว่าล้มเหลวหรือสำเร็จและเปลี่ยนเส้นทางไปยังหน้าอื่นเมื่อประสบความสำเร็จ ฉันพบว่า jquery Ajax ใช้งานง่ายกว่ามากโดยเฉพาะอย่างยิ่งเมื่อฉันใช้ไลบรารีเพื่อสิ่งอื่นอยู่แล้ว

คุณสามารถค้นหาเอกสารเกี่ยวกับ jquery ajax ได้ที่นี่แต่ไวยากรณ์มีดังนี้:

jQuery.ajax( options )  

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

jQuery.getJSON( url, data, callback )

jQuery.getScript( url, callback )

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

จากนั้นทำ POST ปกติเพื่อดำเนินการลบและในกรณีส่วนใหญ่มันจะสำเร็จจากนั้นฉันสามารถเปลี่ยนเส้นทางไปที่หน้า Home Index ได้ ในกรณีที่ล้มเหลวให้แสดงมุมมองอื่นพร้อมข้อความแสดงข้อผิดพลาดและการดำเนินการที่เหมาะสมเพื่อให้ผู้ใช้ดำเนินการ เสียงโอเค?
Jeff Widmer

ใช่ว่ามันจะเข้าท่ากว่า
โจเซฟ

ฉันดำเนินการแปลงสิ่งนี้จาก Ajax ส่งไปยัง POST ปกติตามคำแนะนำของโจเซฟ สิ่งนี้ได้ผลดีขึ้นจริง ๆ เนื่องจากทำให้ฉันมีวิธีที่สะอาดกว่าในการจัดการข้อความยืนยันการลบ
Jeff Widmer

6

การใช้JavaScriptจะทำงานได้อย่างแน่นอน

คุณยังสามารถใช้Contentหากนี่เป็นสไตล์ของคุณมากขึ้น

ตัวอย่าง:

ตัวควบคุม MVC

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

Javascript

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

ขอขอบคุณ! สิ่งนี้ช่วยฉันได้จริงๆ
ดี

5

คุณสามารถเขียนใน Ajax Success ได้ดังนี้:

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

แล้วสิ่งนี้ล่ะ:

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

แล้ว

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

หรือ

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

1

ฉันจำเป็นต้องทำสิ่งนี้เพราะฉันมีแบบฟอร์มเข้าสู่ระบบ ajax เมื่อผู้ใช้เข้าสู่ระบบสำเร็จฉันเปลี่ยนเส้นทางไปยังเพจใหม่และสิ้นสุดการร้องขอก่อนหน้านี้เนื่องจากเพจอื่นจัดการการเปลี่ยนเส้นทางกลับไปยังบุคคลที่เกี่ยวข้อง (เนื่องจากเป็นระบบ STS SSO)

อย่างไรก็ตามฉันยังต้องการให้มันทำงานกับ javascript ที่ปิดใช้งานซึ่งเป็นส่วนเชื่อมต่อการเข้าสู่ระบบส่วนกลางดังนั้นฉันจึงคิดสิ่งนี้ขึ้นมา

    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

คุณก็สามารถทำชนิดของตัวกรองการตอบสนองของอาแจ็กซ์บางอย่างสำหรับการตอบสนองกับ incomming $ .ajaxSetup หากการตอบสนองมีการเปลี่ยนเส้นทาง MVC คุณสามารถประเมินนิพจน์นี้ได้ทางด้าน JS ตัวอย่างโค้ดสำหรับ JS ด้านล่าง:

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

หากข้อมูลคือ: "window.location = '/ Acount / Login'"ด้านบนตัวกรองจะตรวจจับและประเมินเพื่อทำการเปลี่ยนเส้นทาง


0

ฉันไม่พอใจกับคำตอบที่ดีที่สุดของโจเซฟแทนที่จะแก้ไขปัญหาที่ถูกต้องเขาบอกว่านี่เป็นการใช้งานที่ไม่ถูกต้อง ในความเป็นจริงมีหลายสถานที่ตัวอย่างเช่นหากคุณกำลังแปลงโค้ดเบสเก่าให้เป็นโค้ดที่ไม่ได้ใช้งานและคุณจำเป็นต้องใช้มัน ในการเขียนโปรแกรมไม่มีข้อแก้ตัวเพราะไม่เพียง แต่คุณเท่านั้นที่เขียนโค้ดนักพัฒนาที่ไม่ดีและดีทั้งหมดและคุณต้องทำงานเคียงข้างกัน ดังนั้นหากฉันไม่เปลี่ยนเส้นทางโค้ดใน ajax นักพัฒนาเพื่อนของฉันสามารถบังคับให้ฉันแก้ปัญหาได้ เช่นเดียวกับที่ฉันชอบใช้ไซต์ที่มีลวดลายของ AMD หรือ mvc4 ทั้งหมดและ บริษัท ของฉันสามารถทำให้ฉันอยู่ห่างจากมันได้เป็นเวลาหนึ่งปี

เรามาพูดถึงวิธีแก้ปัญหากันเลย

ฉันได้ทำการจัดการคำขอและการตอบกลับของ ajax แล้ววิธีที่ง่ายที่สุดที่ฉันพบคือการส่งรหัสสถานะไปยังไคลเอนต์และมีฟังก์ชันจาวาสคริปต์มาตรฐานหนึ่งฟังก์ชันเพื่อทำความเข้าใจรหัสเหล่านั้น หากฉันเพียงแค่ส่งรหัสตัวอย่าง 13 อาจหมายถึงการเปลี่ยนเส้นทาง

ดังนั้นการตอบสนองของ json เช่น {statusCode: 13, messsage: '/ home / logged-in'} แน่นอนว่ามีรูปแบบต่างๆมากมายที่เสนอเช่น {status: 'success', code: 13, url: '/ home / logged-in ', ข้อความ:' คุณเข้าสู่ระบบแล้ว '}

ฯลฯ ขึ้นอยู่กับตัวเลือกของข้อความมาตรฐานของคุณเอง

โดยปกติฉันรับช่วงจากคลาส Controller พื้นฐานและเลือกการตอบสนองมาตรฐานเช่นนี้

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

เกี่ยวกับการใช้ $ .ajax intead ของ Ajax BeginForm ฉันชอบที่จะใช้ Jquery ajax และฉันทำ แต่อีกครั้งมันไม่ใช่ฉันในโลกทั้งใบในการตัดสินใจฉันมีแอปพลิเคชันที่เต็มไปด้วย Ajax BeginForm และแน่นอนฉันไม่ได้ทำเช่นนั้น แต่ฉันต้องอยู่กับมัน

ดังนั้นจึงมีการโทรกลับที่ประสบความสำเร็จในรูปแบบเริ่มต้นเช่นกันคุณไม่จำเป็นต้องใช้ jquery ajax เพื่อใช้การโทรกลับบางอย่างเกี่ยวกับที่นี่ Ajax BeginForm, Calls Action, Returns JSON, ฉันจะเข้าถึงวัตถุ JSON ในฟังก์ชัน OnSuccess JS ของฉันได้อย่างไร

ขอบคุณ


0

หากคุณเปลี่ยนเส้นทางจากคลาส JavaScript

มุมมองเดียวกัน - ตัวควบคุมที่แตกต่างกัน

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

ไม่ใช่มุมมองเดียวกัน

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

0

เพิ่มคลาสตัวช่วย:

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

จากนั้นเรียกร้องให้ดำเนินการของคุณ:

this.RedirectTo ("ดัชนี", "ปูนซีเมนต์");

เพิ่มรหัสจาวาสคริปต์ลงในไฟล์หรือไฟล์เลย์เอาต์ที่รวมจาวาสคริปต์เพื่อสกัดกั้นคำขอ 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

ดังที่เบนฟอสเตอร์บอกว่าคุณสามารถส่งคืน Javascripts ได้และมันจะนำคุณไปยังหน้าที่ต้องการ

ในการโหลดหน้าในหน้าปัจจุบัน:

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

ในการโหลดหน้าในแท็บใหม่:

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

0

คุณสามารถรับการเปลี่ยนเส้นทางแบบไม่ใช้ js จากการโทร ajax ได้โดยการใส่หนึ่งในแท็กการรีเฟรชเมตาเหล่านั้น สิ่งนี้ดูเหมือนจะใช้งานได้: return Content("<meta http-equiv=\"refresh\" content=\"0;URL='" + @Url.Action("Index", "Home") + "'\" />");

หมายเหตุ: ฉันพบว่าการรีเฟรชเมตาถูกปิดใช้งานโดยอัตโนมัติโดย Firefox การแสดงผลนี้ไม่มีประโยชน์มากนัก

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.