MVC 3: ¿Cómo representar una vista sin su página de diseño cuando se carga a través de ajax?

153

Estoy aprendiendo sobre la mejora progresiva y tengo una pregunta sobre las vistas AJAXifying. En mi proyecto MVC 3 tengo una página de diseño, una página de inicio de vista y dos vistas simples.

La página viewstart está en la raíz de la carpeta Vistas y, por lo tanto, se aplica a todas las vistas. Especifica que todas las vistas deben usarse _Layout.cshtmlpara su página de diseño. La página de diseño contiene dos enlaces de navegación, uno para cada vista. Los enlaces se utilizan @Html.ActionLink()para representarse en la página.

Ahora he agregado jQuery y quiero secuestrar estos enlaces y usar Ajax para cargar su contenido en la página dinámicamente.

<script type="text/javascript">
    $(function () {
        $('#theLink').click(function () {
            $.ajax({
                url: $(this).attr('href'),
                type: "GET",
                success: function (response) {
                    $('#mainContent').html(response);
                }
            });
            return false;
        });
    });
</script>

Hay dos formas en que puedo pensar para hacer esto, pero no me gusta ninguna de las dos:

1) Puedo tomar todo el contenido de la Vista y colocarlo en una vista parcial, luego hacer que la vista principal llame a la vista parcial cuando se procesa. De esa manera, usando Request.IsAjaxRequest()el controlador, puedo devolver View()o regresar en PartialView()función de si la solicitud es o no una solicitud de Ajax. No puedo devolver la vista normal a la solicitud de Ajax porque luego usaría la página de diseño y obtendría una segunda copia de la página de diseño inyectada. Sin embargo, no me gusta esto porque me obliga a crear vistas vacías con solo una @{Html.RenderPartial();}en ellas para las solicitudes GET estándar.

    public ActionResult Index()
    {
        if (Request.IsAjaxRequest())
            return PartialView("partialView");
        else
            return View();
    }

Luego, en Index.cshtml, haga esto:

@{Html.RenderPartial("partialView");}

2) Puedo eliminar la designación de diseño de _viewstart y especificarla manualmente cuando la solicitud NO es Ajax:

    public ActionResult Index()
    {
        if (Request.IsAjaxRequest())
            return View(); // Return view with no master.
        else
            return View("Index", "_Layout"); // Return view with master.
    }

¿Alguien tiene una mejor sugerencia? ¿Hay alguna manera de devolver una vista sin su página de diseño? Sería mucho más fácil decir explícitamente "no incluir su diseño" si se trata de una solicitud ajax, que incluir explícitamente el diseño si no es un ajax.

Chev
fuente

Respuestas:

259

En ~/Views/ViewStart.cshtml :

@{
    Layout = Request.IsAjaxRequest() ? null : "~/Views/Shared/_Layout.cshtml";
}

y en el controlador:

public ActionResult Index()
{
    return View();
}
Darin Dimitrov
fuente
3
¿Se puede especificar esto en el viewstart?
Chev
10
@ Matt Greer, lo llamas desagradable, lo llamo SECO, cosas subjetivas de todos modos :-)
Darin Dimitrov
2
Tengo que admitir que no me gustó al principio, pero la cantidad de código que guarda parece superar con creces su desventaja. Es un simple booleano si y realmente no impone mucha OMI. Me gusta más que cortar mis métodos de acción por la mitad cada vez. Además, me impide hacer lo que dijiste Matt y, potencialmente, seguir dos caminos lógicos gigantes en el método de acción. O escribo la acción para que funcione igual en ambos casos, o escribo una nueva acción.
Chev
1
¿no podría hacer esto en un controlador base, establecer una propiedad en ViewData y usarla? Entonces la línea sería Layout = ViewBag.LayoutFile.
RPM1984
2
Supongo que podría, pero ¿realmente por qué crear un controlador base para una pequeña línea?
Chev
92

Simplemente ponga el siguiente código en la parte superior de la página

@{
    Layout = "";
}
roncansan
fuente
44
Esto no funciona porque quiero poder activar o desactivar el diseño en función de si se solicita o no a través de AJAX. Esto solo le permite desactivar el diseño, no alternarlo.
Chev
44
¿Por qué esto tiene votaciones? por favor explique, así que también lo votaré.
Usman Younas
1
@UsmanY. No necesita votarlo. Pero lo hago. Mi argumento es ir a google.com.pk/#q=mvc3%20view%20without%20layout . Y es la respuesta perfecta a esa consulta.
Sami
3
El tema trata sobre alternar el diseño en dos escenarios diferentes. Esta respuesta simplemente establece que el diseño esté vacío, sin importar cuál sea el escenario.
Rajshekar Reddy
Amigo, esto funciona y es realmente agradable. El escenario que uso: el usuario no autorizado intenta iniciar sesión, ¡uno no quiere que la página de error muestre enlaces y así sucesivamente a un usuario no autorizado! Por supuesto, ¡funciona para todo lo demás también!
JosephDoggie
13

Prefiero y uso tu opción n. ° 1. No me gusta el n. ° 2 porque para mí View()implica que está devolviendo una página completa. Debería ser una página HTML completamente desarrollada y válida una vez que el motor de visualización haya terminado con ella. PartialView()fue creado para devolver fragmentos arbitrarios de HTML.

No creo que sea un gran problema tener una vista que solo llame parcial. Todavía está SECO y le permite usar la lógica del parcial en dos escenarios.

A muchas personas no les gusta fragmentar las rutas de llamadas de su acción Request.IsAjaxRequest(), y puedo apreciar eso. Pero en mi opinión, si todo lo que está haciendo es decidir si llamar View()o no PartialView(), la sucursal no es un gran problema y es fácil de mantener (y probar). Si te encuentras usando IsAjaxRequest()para determinar grandes porciones de cómo se desarrolla tu acción, probablemente sea mejor hacer una acción AJAX por separado.

Matt Greer
fuente
13

Cree dos diseños: 1. diseño vacío, 2. diseño principal y luego escriba en el archivo _viewStart este código:

@{
if (Request.IsAjaxRequest())
{
    Layout = "~/Areas/Dashboard/Views/Shared/_emptyLayout.cshtml";
}
else
{
    Layout = "~/Areas/Dashboard/Views/Shared/_Layout.cshtml";
}}

por supuesto, tal vez no sea la mejor solución

Arash Karami
fuente
8

No tiene que crear una vista vacía para esto.

En el controlador:

if (Request.IsAjaxRequest())
  return PartialView();
else
  return View();

devolver un PartialViewResult anulará la definición del diseño al representar la respuesta.

Souhaieb Besbes
fuente
2

Con ASP.NET 5 ya no hay ninguna variable de solicitud disponible. Puede acceder a él ahora con Context.Request

Además, ya no existe el método IsAjaxRequest (), debe escribirlo usted mismo, por ejemplo en Extensions \ HttpRequestExtensions.cs

using System;
using Microsoft.AspNetCore.Http;

namespace Microsoft.AspNetCore.Mvc
{
    public static class HttpRequestExtensions
    {
        public static bool IsAjaxRequest(this HttpRequest request)
        {
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }

            return (request.Headers != null) && (request.Headers["X-Requested-With"] == "XMLHttpRequest");
        }
    }
}

Busqué por un tiempo en esto y espero que también ayude a otros;)

Recurso: https://github.com/aspnet/AspNetCore/issues/2729

Drotak
fuente
-5

Para una aplicación Ruby on Rails, pude evitar que se cargara un diseño especificando render layout: falseen la acción del controlador que quería responder con ajax html.

usuario4381244
fuente
66
etiquetas: c # asp.net, no ruby
MrKekson