Comment obtenir une réponse ASP.NET MVC Ajax pour rediriger vers une nouvelle page au lieu d'insérer une vue dans UpdateTargetId?


88

J'utilise Ajax.BeginForm pour créer un formulaire qui fera une publication ajax sur une certaine action du contrôleur, puis si l'action réussit, l'utilisateur doit être redirigé vers une autre page (si l'action échoue, un message d'état s'affiche à l'aide de 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]
   }

Si la suppression réussit, je renvoie un résultat de redirection:

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

Mais la vue Home Controller Index est chargée dans UpdateTargetId et je me retrouve donc avec une page dans une page. Deux choses auxquelles je pense:

  1. Soit j'architecte ce mal et je devrais gérer ce type d'action différemment (sans utiliser ajax).
  2. Au lieu de renvoyer un résultat de redirection, retournez une vue contenant du javascript qui effectue la redirection côté client.

Quelqu'un a-t-il des commentaires sur le # 1? Ou si # 2 est une bonne solution, à quoi ressemblerait la "vue javascript de redirection"?

Réponses:


171

Vous pouvez utiliser JavascriptResultpour y parvenir.

Pour rediriger:

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

Pour recharger la page actuelle:

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

Semble l'option la plus simple.


4
Génial ... m'a aidé.
CrazyCoderz

1
Je suis d'accord, c'est la bonne approche. Cette réponse stackoverflow.com/a/2841608/498969 montre comment vous pouvez appliquer cette fonctionnalité par défaut à l'aide d'un contrôleur de base.
Adam Spicer

@Ben Foster: L'utilisation de ce parcours tente d'ouvrir l'url http :: window.location ... J'ai posté ceci en tant que question distincte dans stackoverflow.com/questions/13896307/…
Andrus

30
Si vous souhaitez rediriger vers un contrôleur de votre projet, vous pouvez utiliser l'assistant URL pour vous. Par exemple:return JavaScript( "window.location = '" + Url.Action("Edit","Dispatch") + "'" );
Chris Morgan

2
Court. Facile. Excellent. Génial!
Vikram

30

Vous pouvez renvoyer un JSON avec l'URL et modifier le window.location à l'aide de JavaScript côté client. Je préfère cette façon que d'appeler une fonction JavaScript à partir du serveur, ce qui, je pense, brise la séparation des préoccupations.

Du côté serveur:

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

Côté client:

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

Bien sûr, vous pouvez ajouter plus de logique car il pourrait y avoir une erreur côté serveur et dans ce cas, la propriété result pourrait indiquer cette situation et éviter la redirection.


12

Le comportement que vous essayez de produire n'est pas vraiment mieux réalisé avec AJAX. AJAX serait mieux utilisé si vous ne vouliez mettre à jour qu'une partie de la page, pas complètement rediriger vers une autre page. Cela va vraiment à l'encontre de l'objectif d'AJAX.

Je suggérerais de ne pas utiliser AJAX avec le comportement que vous décrivez.

Vous pouvez également essayer d'utiliser jquery Ajax, qui soumettra la demande, puis vous spécifiez un rappel lorsque la demande se termine. Dans le rappel, vous pouvez déterminer s'il a échoué ou réussi et rediriger vers une autre page en cas de succès. J'ai trouvé jquery Ajax beaucoup plus facile à utiliser, d'autant plus que j'utilise déjà la bibliothèque pour d'autres choses de toute façon.

Vous pouvez trouver de la documentation sur jquery ajax ici , mais la syntaxe est la suivante:

jQuery.ajax( options )  

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

jQuery.getJSON( url, data, callback )

jQuery.getScript( url, callback )

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

Alors faites simplement un POST régulier à l'action Supprimer et dans la plupart des cas, cela réussira, puis je pourrai rediriger vers la page Index d'accueil. Dans les cas où cela échouerait, affichez une vue différente avec les messages d'erreur et l'action appropriée que l'utilisateur doit entreprendre. Ça va?
Jeff Widmer

Ouais, ça aurait plus de sens.
Joseph

Je suis allé de l'avant avec la conversion d'une soumission Ajax à un POST régulier selon la recommandation de Joseph. Cela a mieux fonctionné car cela m'a donné un moyen plus propre de gérer le message de confirmation de suppression.
Jeff Widmer

12

Bien que n'étant pas élégant, fonctionne pour moi dans certaines situations.

Manette

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

Modèle

    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
Pourquoi pas élégant? C'est fortement typé et c'est clair. J'aime cette approche. +1
T-moty

6

L'utilisation JavaScriptfera certainement le travail.

Vous pouvez également utiliser Contentsi c'est plus votre style.

Exemple:

Contrôleur MVC

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

Javascript

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

Je vous remercie! Cela m'a vraiment aidé.
dee

5

Vous pouvez simplement écrire dans Ajax Success comme ci-dessous:

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

Que dis-tu de ça :

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

Puis

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

Ou

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

1

J'avais besoin de le faire car j'ai un formulaire de connexion ajax. Lorsque les utilisateurs se connectent avec succès, je redirige vers une nouvelle page et met fin à la demande précédente car l'autre page gère la redirection vers la partie de confiance (car il s'agit d'un système SSO STS).

Cependant, je voulais également que cela fonctionne avec javascript désactivé, étant le saut de connexion central et tout, alors j'ai trouvé ceci,

    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

Vous pouvez simplement faire une sorte de filtre de réponse ajax pour les réponses entrantes avec $ .ajaxSetup . Si la réponse contient une redirection MVC, vous pouvez évaluer cette expression côté JS. Exemple de code pour JS ci-dessous:

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

Si les données sont: "window.location = '/ Acount / Login'" ci-dessus, le filtre attrapera cela et évaluera pour effectuer la redirection.


0

Je ne suis pas satisfait de la meilleure réponse du Joseph, au lieu de résoudre le problème correct, il a dit que ce n'était pas le bon cas d'utilisation. En fait, il existe de nombreux endroits, par exemple si vous convertissez une ancienne base de code en code ajaxifié et que vous en avez BESOIN, alors vous en avez BESOIN. En programmation, il n'y a aucune excuse car ce n'est pas seulement vous qui codez tous ses mauvais et bons développeurs et vous devez travailler côte à côte. Donc, si je ne code pas la redirection en ajax, mon collègue développeur peut me forcer à avoir une solution pour cela. Tout comme j'aime utiliser tous les sites à motifs AMD ou mvc4, et mon entreprise peut m'en éloigner pendant un an.

Alors parlons de la solution maintenant.

J'ai fait un sacré traitement des demandes et des réponses ajax et le moyen le plus simple que j'ai découvert était d'envoyer des codes d'état au client et d'avoir une fonction javascript standard pour comprendre ces codes. Si j'envoie simplement par exemple le code 13, cela peut signifier une redirection.

Donc une réponse json comme {statusCode: 13, messsage: '/ home / log-in'} bien sûr il y a des tonnes de variantes proposées comme {status: 'success', code: 13, url: '/ home / log-in ', message:' Vous êtes connecté maintenant '}

etc, donc à votre propre choix de messages standard

Habituellement, j'hérite de la classe Controller de base et je mets mon choix de réponses standard comme celle-ci

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

À propos de l'utilisation de $ .ajax au lieu d'Ajax.BeginForm J'adorerais utiliser Jquery ajax et je le fais, mais encore une fois, ce n'est pas à moi au monde de prendre des décisions.J'ai une application pleine d'Ajax.BeginForm et bien sûr je ne l'ai pas fait. Mais je dois vivre avec.

Il y a donc un rappel de succès dans la forme de début aussi, vous n'avez pas besoin d'utiliser jquery ajax pour utiliser les rappels Quelque chose à ce sujet ici Ajax.BeginForm, Appelle une action, renvoie JSON, Comment accéder à l'objet JSON dans ma fonction OnSuccess JS?

Merci


0

Si vous êtes redirigé depuis la classe JavaScript

même point de vue - contrôleur différent

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

n'est pas le même point de vue

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

0

Ajoutez une classe d'assistance:

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

Appelez ensuite votre action:

this.RedirectTo ("Index", "Cement");

Ajoutez du code javascript à n'importe quel fichier global javascript inclus ou fichier de mise en page pour intercepter toutes les requêtes 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

Comme le dit Ben Foster, vous pouvez renvoyer les Javascripts et cela vous redirigera vers la page souhaitée.

Pour charger la page dans la page actuelle:

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

Pour charger la page dans le nouvel onglet:

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

0

Vous pouvez obtenir une redirection non basée sur js à partir d'un appel ajax en insérant l'une de ces balises meta refresh. Cela semble fonctionner ici: return Content("<meta http-equiv=\"refresh\" content=\"0;URL='" + @Url.Action("Index", "Home") + "'\" />");

Remarque: j'ai découvert que les mises à jour méta sont automatiquement désactivées par Firefox, ce qui rend cela peu utile.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.