MVC 3: Comment rendre une vue sans sa page de mise en page lorsqu'elle est chargée via ajax?

153

J'apprends à propos de Progressive Enhancement et j'ai une question sur les vues AJAXifying. Dans mon projet MVC 3, j'ai une page de mise en page, une page de démarrage et deux vues simples.

La page viewstart se trouve à la racine du dossier Views et s'applique donc à toutes les vues. Il spécifie que toutes les vues doivent être utilisées _Layout.cshtmlpour leur page de mise en page. La page de mise en page contient deux liens de navigation, un pour chaque vue. Les liens sont utilisés @Html.ActionLink()pour s'afficher sur la page.

Maintenant, j'ai ajouté jQuery et je souhaite détourner ces liens et utiliser Ajax pour charger leur contenu sur la page de manière dynamique.

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

Il y a deux façons de le faire, mais je n'aime pas particulièrement l'une ou l'autre:

1) Je peux prendre tout le contenu de la vue et les placer dans une vue partielle, puis demander à la vue principale d'appeler la vue partielle lorsqu'elle est rendue. De cette façon, en utilisant Request.IsAjaxRequest()dans le contrôleur, je peux retourner View()ou retourner en PartialView()fonction du fait que la demande est ou non une demande Ajax. Je ne peux pas retourner la vue normale à la demande Ajax car elle utiliserait alors la page de mise en page et j'obtiendrais une deuxième copie de la page de mise en page injectée. Cependant, je n'aime pas cela car cela m'oblige à créer des vues vides avec juste un @{Html.RenderPartial();}en eux pour les requêtes GET standard.

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

Ensuite, dans Index.cshtml, procédez comme suit:

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

2) Je peux supprimer la désignation de mise en page de _viewstart et la spécifier manuellement lorsque la demande n'est PAS Ajax:

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

Quelqu'un a-t-il une meilleure suggestion? Existe-t-il un moyen de renvoyer une vue sans sa page de mise en page? Il serait beaucoup plus facile de dire explicitement "ne pas inclure votre mise en page" s'il s'agit d'une requête ajax, que d'inclure explicitement la mise en page si ce n'est pas un ajax.

Chev
la source

Réponses:

259

Dans ~/Views/ViewStart.cshtml:

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

et dans le contrôleur:

public ActionResult Index()
{
    return View();
}
Darin Dimitrov
la source
3
Cela peut-il être spécifié dans le viewstart?
Chev
10
@Matt Greer, vous l'appelez méchant, je l'appelle DRY, des trucs subjectifs quand même :-)
Darin Dimitrov
2
Je dois admettre que je ne l'ai pas aimé au début, mais la quantité de code qu'il enregistre semble dépasser de loin son inconvénient. C'est un simple booléen si et n'impose pas vraiment beaucoup d'OMI. Je l'aime mieux que de diviser par deux mes méthodes d'action à chaque fois. De plus, cela m'empêche de faire ce que vous avez dit Matt et de suivre potentiellement deux chemins logiques géants dans la méthode d'action. Soit j'écris l'action pour qu'elle fonctionne de la même manière dans les deux cas, soit j'écris une nouvelle action.
Chev
1
ne pourriez-vous pas faire cela dans un contrôleur de base, définir une propriété dans ViewData et l'utiliser? Alors la ligne serait Layout = ViewBag.LayoutFile.
RPM1984
2
Je suppose que je pourrais, mais vraiment pourquoi créer un baseController pour une petite ligne?
Chev
92

Mettez simplement le code suivant en haut de la page

@{
    Layout = "";
}
Roncansan
la source
4
Cela ne fonctionne pas car je veux pouvoir activer ou désactiver la mise en page selon qu'elle est demandée ou non via AJAX. Cela vous permet uniquement de désactiver la mise en page, pas de la basculer.
Chev
4
Pourquoi cela a des votes? les pls expliquent donc je voterai aussi.
Usman Younas
1
@UsmanY. Vous n'avez pas besoin de voter. Mais je fais. Mon argument va sur google.com.pk/#q=mvc3%20view%20without%20layout . Et c'est la réponse parfaite à cette question.
Sami
3
Le sujet est sur le basculement de la mise en page sur deux scénarios différents. Cette réponse définit simplement la mise en page sur vide, quel que soit le scénario.
Rajshekar Reddy
Mec, ça marche et c'est vraiment sympa. Le scénario que j'utilise: l'utilisateur non autorisé essaie de se connecter, on ne veut pas que la page d'erreur affiche des liens et ainsi de suite à un utilisateur non autorisé! Bien sûr, cela fonctionne aussi pour tout le reste!
JosephDoggie
13

Je préfère et j'utilise votre option n ° 1. Je n'aime pas le n ° 2 parce que pour moi, View()vous renvoyez une page entière. Il doit s'agir d'une page HTML complète et valide une fois que le moteur de visualisation en a terminé avec elle. PartialView()a été créé pour renvoyer des morceaux arbitraires de HTML.

Je ne pense pas que ce soit un gros problème d'avoir un point de vue qui appelle simplement un partiel. Il est toujours SEC et vous permet d'utiliser la logique du partiel dans deux scénarios.

Beaucoup de gens n'aiment pas fragmenter les chemins d'appel de leur action avec Request.IsAjaxRequest(), et je peux l'apprécier. Mais l'OMI, si tout ce que vous faites est de décider d'appeler View()ou PartialView()alors la succursale n'est pas un gros problème et est facile à maintenir (et à tester). Si vous vous retrouvez à utiliser IsAjaxRequest()pour déterminer de grandes parties de la façon dont votre action se déroule, il est probablement préférable de créer une action AJAX séparée.

Matt Greer
la source
13

Créez deux mises en page: 1. mise en page vide, 2. mise en page principale, puis écrivez dans le fichier _viewStart ce code:

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

bien sûr, ce n'est peut-être pas la meilleure solution

Arash Karami
la source
8

Vous n'êtes pas obligé de créer une vue vide pour cela.

Dans le contrôleur:

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

renvoyer un PartialViewResult remplacera la définition de disposition lors du rendu de la réponse.

Souhaieb Besbes
la source
2

Avec ASP.NET 5, aucune variable de demande n'est plus disponible. Vous pouvez y accéder maintenant avec Context.

De plus, il n'y a plus de méthode IsAjaxRequest (), vous devez l'écrire vous-même, par exemple dans 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");
        }
    }
}

J'ai cherché un moment à ce sujet et j'espère que cela aidera aussi d'autres;)

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

Drotak
la source
-5

Pour une application Ruby on Rails, j'ai pu empêcher le chargement d'une mise en page en spécifiant render layout: falsedans l'action du contrôleur que je voulais répondre avec ajax html.

user4381244
la source
6
tags: c # asp.net, pas rubis
MrKekson