web-dev-qa-db-fra.com

Redirection AngularJS sans pousser un état historique

Je travaille sur une application AngularJS qui a une route catch all (par exemple, .when('/:slug', {...)) qui est nécessaire pour prendre en charge les formats d'URL hérités d'une version précédente (non angulaire) de l'application. Le contrôleur qui répond à l'interception essaie de tirer un objet associé et, s'il n'est pas trouvé, redirige vers une page 404 en utilisant le $location.path méthode. Cela fonctionne pour amener l'utilisateur à la page 404, mais lorsque l'utilisateur revient dans son navigateur, il le ramène à la page qui l'a forcé à la page 404 en premier lieu et ils finissent par être incapables d'échapper au cycle.

Ma question est de savoir s'il existe 1) un meilleur modèle pour gérer cette situation, ou 2) s'il existe un moyen de rediriger l'utilisateur qui ne force pas un état d'historique dans le navigateur?

35
kyleder

Vous pouvez modifier l'URL sans ajouter à l'état de l'historique, trouvé ici sous "Remplacer la méthode". C'est en fait la même chose que d'appeler history.replaceState () de HTML5.

$location.path('/someNewPath').replace();

Je n'ai pas trouvé qu'il était possible de changer la vue sans changer l'url. La seule méthode pour changer la vue, que j'ai trouvée, est de changer le chemin de l'emplacement.

58
thrashr888

Le fonctionnement normal du système d'itinéraire est pour le $route service pour surveiller le $locationChangeSuccess événement, puis commencez à charger un itinéraire. Une fois le chargement du modèle terminé, l'exécution des étapes de résolution et l'instanciation du contrôleur, il diffuse à son tour un $routeChangeSuccess un événement. Cette $routeChangeSuccess est surveillé par le ng-view directive, et c'est ainsi qu'il sait échanger les modèles et les étendues une fois que la nouvelle route est prête.

Avec tout ce qui précède dit, il peut être utile que le code d'application émule le comportement du $route service en mettant à jour l'itinéraire actuel et en émettant l'événement de changement d'itinéraire pour obtenir la vue à mettre à jour:

var errorRoute = $route.routes[null]; // assuming the "otherwise" route is the 404
// a route instance is an object that inherits from the route and adds
// new properties representing the routeParams and locals.
var errorRouteInstance = angular.inherit(
    errorRoute,
    {
        params: {},
        pathParams: {},
    }
);
// The $route service depends on this being set so it can recover the route
// for a given route instance.
errorRouteInstance.$$route = errorRoute;

var last = $route.current;
$route.current = errorRouteInstance;

// the ng-view code doesn't actually care about the parameters here,
// since it goes straight to $route.current, but we should include
// them anyway since other code might be listening for this event
// and depending on these params to behave as documented.
$rootScope.broadcast('$routeChangeSuccess', errorRoute, last);

Ce qui précède suppose que votre itinéraire "sinon" ne comporte aucune étape de "résolution". Il suppose également qu'il n'attend pas de $routeParams, ce qui est bien sûr vrai pour la route "sinon" mais peut ne pas être vrai si vous utilisez une route différente.

On ne sait pas exactement ce qui précède en fonction des détails de mise en œuvre par rapport à l'interface. Le $routeChangeSuccess l'événement est certainement documenté, mais le $$route La propriété de l'instance d'itinéraire semble être un détail d'implémentation du système d'itinéraire étant donné son nom à double signe dollar. Le détail selon lequel la route "sinon" est conservée dans la table de routage avec la clé null est peut-être aussi un détail d'implémentation. Donc, avec tout cela dit, ce comportement pourrait ne pas rester fonctionnel dans les futures versions d'AngularJS.

Pour plus d'informations, vous pouvez vous référer à le ng-view code qui gère cet événement , qui est finalement ce que le code ci-dessus essaie de plaire, ainsi que le code émetteur d'événement que j'ai utilisé comme base pour l'exemple ci-dessus. Comme vous pouvez le déduire de ces liens, les informations contenues dans ce post sont dérivées de la dernière branche principale d'AngularJS, qui au moment de la rédaction est étiquetée comme 1.2.0-snapshot.

3
Martin Atkins