Angular – roteador ui obter estado anterior

Existe uma maneira de obter o estado anterior do estado atual?

Por exemplo, eu gostaria de saber qual era o estado anterior antes do estado atual B (onde o estado anterior teria sido o estado A).

Não consigo encontrá-lo nas páginas de documentação do github do roteador ui.

O ui-router não rastreia o estado anterior uma vez que ele transita, mas o evento $stateChangeSuccess é transmitido no $rootScope quando o estado é alterado.

Você deve ser capaz de capturar o estado anterior daquele evento ( from é o estado que você está deixando):

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

Eu uso resolver para salvar os dados do estado atual antes de passar para o novo estado:

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

Por questões de legibilidade, vou colocar a minha solução (baseada na análise do stu.salsbury) aqui.

Adicione este código ao modelo abstrato do seu aplicativo para que ele seja executado em todas as páginas.

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

Mantém o controle das alterações no rootScope. É muito útil.

No exemplo a seguir, criei um decorator (executado apenas uma vez por aplicativo na fase de configuração) e adiciona uma propriedade extra ao serviço $state , portanto, essa abordagem não adiciona variables globais a $rootscope e não requer adicionar nenhuma dependência extra a outras serviços que $state .

No meu exemplo, eu precisava redirect um usuário para a página de índice quando ele já estava conectado e quando não deveria redirecioná-lo para a página anterior “protegida” depois de fazer login.

Os únicos serviços desconhecidos (para você) que eu uso são authenticationFactory e appSettings :

  • authenticationFactory apenas administra o login do usuário. Neste caso eu uso apenas um método para identificar se o usuário está logado ou não.
  • appSettings são constantes apenas para não usar strings em todos os lugares. appSettings.states.login e appSettings.states.register contêm o nome do estado para o URL de login e registro.

Em seguida, em qualquer controller / service etc, você precisa injetar o serviço $state e você pode acessar o URL atual e anterior como este:

  • Corrente: $state.current.name
  • Anterior: $state.previous.route.name

No console do Chrome:

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

Implementação:

(Estou usando o angular-ui-router v0.2.17 e o 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); 

Adicione uma nova propriedade chamada {previous} para $ state em $ 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; ... } 

Agora, qualquer lugar que você precise pode usar $ state, você terá access prévio

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

E use assim:

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

Eu uso uma abordagem semelhante ao que Endy Tjahjono faz.

O que eu faço é salvar o valor do estado atual antes de fazer uma transição. Vamos ver em um exemplo; imagine isso dentro de uma function executada ao clicar em qualquer coisa que desencadeie a transição:

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

A chave aqui é o object params (um mapa dos parâmetros que serão enviados para o estado) -> { previousState : { name : $state.current.name } }

Nota: note que estou apenas “salvando” o atributo name do object $ state, porque é a única coisa que eu preciso para salvar o estado. Mas poderíamos ter todo o object de estado.

Então, diga “o que quer que” tenha sido definido assim:

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

Aqui, o ponto chave é o object params.

 params : { previousState: null, } 

Então, dentro desse estado, podemos obter o estado anterior assim:

 $state.params.previousState.name 

Eu estou preso com o mesmo problema e encontrar a maneira mais fácil de fazer isso …

 //Html  

OU

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

(Se você quiser que seja mais testável, injete o serviço $ window em seu controller e use $ window.history.back ()).

Aqui está uma solução realmente elegante de Chris Thielen ui-router-extras: $ previousState

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

previous é um object que se parece com: { state: fromState, params: fromParams } que fromState é o estado anterior e fromParams são os parâmetros de estado anteriores.

Ok, eu sei que estou atrasado para a festa aqui, mas eu sou novo em angular. Eu estou tentando fazer isso caber no guia estilo John Papa aqui. Eu queria fazer isso reutilizável então eu criei em um bloco. Aqui está o que eu criei:

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

Qualquer crítica sobre este código só me ajudará, então, por favor, deixe-me saber onde posso melhorar este código.

Se você precisar desta funcionalidade e quiser usá-la em mais de um controlador, este é um serviço simples para rastrear o histórico de rotas:

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

onde o ‘core’ em .module (‘core’) seria o nome do seu aplicativo / módulo. Exigir o serviço como uma dependência para o seu controlador, em seguida, em seu controlador, você pode fazer: $scope.routeHistory = RouterTracker.getRouteHistory()

Uma solução muito simples é apenas editar a string $ state.current.name e cortar tudo incluindo e depois do último ‘.’ – você obtém o nome do estado pai. Isso não funciona se você pular muito entre estados porque apenas analisa o caminho atual. Mas se os seus estados corresponderem ao local onde você realmente está, isso funciona.

 var previousState = $state.current.name.substring(0, $state.current.name.lastIndexOf('.')) $state.go(previousState) 

Eu acompanho os estados anteriores em $ rootScope , então, sempre que precisar, vou apenas chamar a linha de código abaixo.

 $state.go($rootScope.previousState); 

Em App.js :

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

Você pode retornar o estado desta forma:

 $state.go($state.$current.parent.self.name, $state.params); 

Um exemplo:

 (function() { 'use strict' angular.module('app') .run(Run); /* @ngInject */ function Run($rootScope, $state) { $rootScope.back = function() { $state.go($state.$current.parent.self.name, $state.params); }; }; })();