web-dev-qa-db-fra.com

Angular - le routeur précédent reçoit l'état précédent

Existe-t-il un moyen de retrouver l'état précédent de l'état actuel?

Par exemple, j'aimerais savoir quel était l'état précédent avant l'état actuel B (où l'état précédent aurait été l'état A).

Je ne parviens pas à le trouver dans les pages doc de github ui-router.

148
Mihai H

ui-router ne suit pas l'état précédent une fois la transition effectuée, mais l'événement $stateChangeSuccess est diffusé sur le $rootScope lorsque l'état change.

Vous devriez pouvoir saisir l'état antérieur de cet événement (from est l'état que vous quittez):

$rootScope.$on('$stateChangeSuccess', function (ev, to, toParams, from, fromParams) {
   //assign the "from" parameter to something
});
130
laurelnaiad

J'utilise resol pour enregistrer les données d'état actuelles avant de passer au nouvel état:

angular.module('MyModule')
.config(['$stateProvider', function ($stateProvider) {
    $stateProvider
        .state('mystate', {
            templateUrl: 'mytemplate.html',
            controller: ["PreviousState", function (PreviousState) {
                if (PreviousState.Name == "mystate") {
                    // ...
                }
            }],
            resolve: {
                PreviousState: ["$state", function ($state) {
                    var currentStateData = {
                        Name: $state.current.name,
                        Params: $state.params,
                        URL: $state.href($state.current.name, $state.params)
                    };
                    return currentStateData;
                }]
            }
        });
}]);
142
Endy Tjahjono

Par souci de lisibilité, je vais placer ici ma solution (basée sur l'anwser de stu.salsbury).

Ajoutez ce code au modèle de résumé de votre application pour qu'il soit exécuté sur toutes les pages.

$rootScope.previousState;
$rootScope.currentState;
$rootScope.$on('$stateChangeSuccess', function(ev, to, toParams, from, fromParams) {
    $rootScope.previousState = from.name;
    $rootScope.currentState = to.name;
    console.log('Previous state:'+$rootScope.previousState)
    console.log('Current state:'+$rootScope.currentState)
});

Assure le suivi des modifications dans rootScope. C'est très pratique.

98
Federico

Dans l'exemple suivant, j'ai créé un decorator (une seule exécution par application lors de la phase de configuration) et ajouté une propriété supplémentaire au service $state, de sorte que cette approche n'ajoute pas . variables globales à $rootscope et n’a pas besoin d’ajouter de dépendance à d’autres services que $state.

Dans mon exemple, je devais rediriger un utilisateur vers la page d'index alors qu'il était déjà connecté et qu'il ne devait pas le rediriger vers la page "protégée" précédente après la connexion.

Les seuls services inconnus (pour vous) que j'utilise sont authenticationFactory et appSettings:

  • authenticationFactory n'administre que l'identifiant de l'utilisateur. Dans ce cas, j'utilise uniquement une méthode pour identifier si l'utilisateur est connecté ou non.
  • appSettings sont des constantes juste pour ne pas utiliser des chaînes partout. appSettings.states.login et appSettings.states.register contiennent le nom de l'état pour l'URL de connexion et d'enregistrement.

Ensuite, dans n'importe quel controller/service etc, vous devez injecter le service $state et vous pouvez accéder aux URL actuelles et précédentes comme ceci:

  • Courant: $state.current.name
  • Précédent: $state.previous.route.name

Depuis la console Chrome:

var injector = angular.element(document.body).injector();
var $state = injector.get("$state");
$state.current.name;
$state.previous.route.name;

mise en œuvre:

(J'utilise angular-ui-router v0.2.17 et angularjs v1.4.9)

(function(angular) {
    "use strict";

    function $stateDecorator($delegate, $injector, $rootScope, appSettings) {
        function decorated$State() {
            var $state = $delegate;
            $state.previous = undefined;
            $rootScope.$on("$stateChangeSuccess", function (ev, to, toParams, from, fromParams) {
                $state.previous = { route: from, routeParams: fromParams }
            });

            $rootScope.$on("$stateChangeStart", function (event, toState/*, toParams, fromState, fromParams*/) {
                var authenticationFactory = $injector.get("authenticationFactory");
                if ((toState.name === appSettings.states.login || toState.name === appSettings.states.register) && authenticationFactory.isUserLoggedIn()) {
                    event.preventDefault();
                    $state.go(appSettings.states.index);
                }
            });

            return $state;
        }

        return decorated$State();
    }

    $stateDecorator.$inject = ["$delegate", "$injector", "$rootScope", "appSettings"];

    angular
        .module("app.core")
        .decorator("$state", $stateDecorator);
})(angular);
14
CodeArtist

Ajouter une nouvelle propriété appelée {previous} à $ state sur $ stateChangeStart

$rootScope.$on( '$stateChangeStart', ( event, to, toParams, from, fromParams ) => {
    // Add {fromParams} to {from}
    from.params = fromParams;

    // Assign {from} to {previous} in $state
    $state.previous = from;
    ...
}

Maintenant, partout où vous en avez besoin, vous pouvez utiliser $ state.

previous:Object
    name:"route name"
    params:Object
        someParam:"someValue"
    resolve:Object
    template:"route template"
    url:"/route path/:someParam"

Et utilisez-le comme ceci:

$state.go( $state.previous.name, $state.previous.params );
12
Luis

Je suis coincé avec le même problème et trouve le moyen le plus simple de le faire ...

//Html
<button type="button" onclick="history.back()">Back</button>

OR

//Html
<button type="button" ng-click="goBack()">Back</button>

//JS
$scope.goBack = function() {
  window.history.back();
};

(Si vous voulez que ce soit plus testable, injectez le service $ window dans votre contrôleur et utilisez $ window.history.back ()).

9
ProCylon

J'utilise une approche similaire à celle de Endy Tjahjono.

Ce que je fais est de sauvegarder la valeur de l'état actuel avant de faire une transition. Permet de voir sur un exemple; imaginez cela dans une fonction exécutée lorsque vous cliquez sur ce qui déclenche la transition:

$state.go( 'state-whatever', { previousState : { name : $state.current.name } }, {} );

La clé ici est l’objet params (une carte des paramètres qui seront envoyés à l’état) -> { previousState : { name : $state.current.name } }

Note: notez que je ne fais que "sauvegarder" l'attribut name de l'objet $ state, car c'est la seule chose dont j'ai besoin pour sauvegarder l'état. Mais nous pourrions avoir l'objet d'état entier.

Ensuite, déclarez "tout ce que" a été défini comme ceci:

.state( 'user-edit', {
  url : 'whatever'
  templateUrl : 'whatever',
  controller: 'whateverController as whateverController',
  params : {
    previousState: null,
  }
});

Ici, le point clé est l’objet params.

params : {
  previousState: null,
}

Ensuite, dans cet état, nous pouvons obtenir l'état précédent comme ceci:

$state.params.previousState.name
8
avcajaraville

Voici une solution vraiment élégante de Chris Thielen i-router-extras: $ previousState

var previous = $previousState.get(); //Gets a reference to the previous state.

previous est un objet qui ressemble à: { state: fromState, params: fromParams } où FromState est l'état précédent et fromParams, les paramètres d'état précédents.

6
Ephraim

Ok, je sais que je suis en retard à la fête ici, mais je suis nouveau à angular. J'essaie de faire en sorte que cela rentre dans le guide de rédaction de John Papa ici. Je voulais faire cela réutilisable alors j'ai créé dans un bloc. Voici ce que je suis venu avec:

previousStateProvider

(function () {
'use strict';

angular.module('blocks.previousState')
       .provider('previousState', previousStateProvider);

previousStateProvider.$inject = ['$rootScopeProvider'];

function previousStateProvider($rootScopeProvider) {
    this.$get = PreviousState;

    PreviousState.$inject = ['$rootScope'];

    /* @ngInject */
    function PreviousState($rootScope) {
        $rootScope.previousParms;
        $rootScope.previousState;
        $rootScope.currentState;

        $rootScope.$on('$stateChangeSuccess', function (ev, to, toParams, from, fromParams) {
            $rootScope.previousParms = fromParams;
            $rootScope.previousState = from.name;
            $rootScope.currentState = to.name;
        });
    }
}
})();

core.module

(function () {
'use strict';

angular.module('myApp.Core', [
    // Angular modules 
    'ngMessages',
    'ngResource',

    // Custom modules 
    'blocks.previousState',
    'blocks.router'

    // 3rd Party Modules
]);
})();

core.config

(function () {
'use strict';

var core = angular.module('myApp.Core');

core.run(appRun);

function appRun(previousState) {
    // do nothing. just instantiating the state handler
}
})();

Toute critique sur ce code ne pourra que m'aider, alors laissez-moi savoir où je peux améliorer ce code.

4
fizch

Si vous avez juste besoin de cette fonctionnalité et souhaitez l'utiliser dans plusieurs contrôleurs, il s'agit d'un service simple pour suivre l'historique des itinéraires:

  (function () {
  'use strict';

  angular
    .module('core')
    .factory('RouterTracker', RouterTracker);

  function RouterTracker($rootScope) {

    var routeHistory = [];
    var service = {
      getRouteHistory: getRouteHistory
    };

    $rootScope.$on('$stateChangeSuccess', function (ev, to, toParams, from, fromParams) {
      routeHistory.Push({route: from, routeParams: fromParams});
    });

    function getRouteHistory() {
      return routeHistory;
    }

    return service;
  }
})();

où le "noyau" dans .module ("noyau") serait le nom de votre application/module. Exiger le service en tant que dépendance de votre contrôleur, puis dans votre contrôleur, vous pouvez faire: $scope.routeHistory = RouterTracker.getRouteHistory()

2
user1970565

Je garde une trace des états précédents dans $ rootScope, donc chaque fois que j'en aurai besoin, j'appellerai simplement la ligne de code ci-dessous.

$state.go($rootScope.previousState);

Dans App.js:

$rootScope.$on('$stateChangeSuccess', function(event, to, toParams, from, fromParams) {
  $rootScope.previousState = from.name;
});
1
Naveen Kumar V

Pour UI-Router (> = 1.0), les événements StateChange sont obsolètes. Pour un guide de migration complet, cliquez ici

Pour obtenir l'état précédent de l'état actuel dans UI-Router 1.0+:

app.run(function ($transitions) {
    $transitions.onSuccess({}, function (trans) {
         // previous state and paramaters
         var previousState = trans.from().name;
         var previousStateParameters = trans.params('from');
    });
});
0
NagarajuRaghava