Angular-UI路由器获得先前状态


152

有没有办法获取当前状态的先前状态?

例如,我想知道当前状态B之前的先前状态是什么(以前的状态本来是状态A)。

我无法在ui-router github文档页面中找到它。


以下答案是正确的,如果文档不够帮助,您还可以从源代码中找到所需的所有信息goo.gl/9B9bH
David Chase

Answers:


133

ui-router转换后不会跟踪以前的状态,但是会在状态更改时$stateChangeSuccess广播该事件$rootScope

您应该能够从该事件中捕获先前状态(from即将离开的状态):

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

3
使用“ from”的示例将是什么?
Paul

这里的“至”和“来自”是指“至州”和“自州”。考虑您以前的URL为localhost:xxxx / employee,控制器为'EmployeesController',则'fromState'的示例为:Object {url:“ / employees”,templateUrl:“ / employees”,控制器:“ EmployeesController”,名称:“员工”}
Ranadheer Reddy 2013年

3
我在摘要中这样做:`$ rootScope.previousState; $ rootScope.currentState; $ rootScope。$ on('$ stateChangeSuccess',function(ev,to,toParams,from,fromParams){$ rootScope.previousState = from.name; $ rootScope.currentState = to.name; console.log('以前的状态: '+ $ rootScope.previousState)console.log('当前状态:'+ $ rootScope.currentState)}); `它跟踪rootScope中的上一个和当前。很方便!
Federico

使用@ endy-tjahjono(stackoverflow.com/a/25945003/2837519)的解决方案更易于使用ui路由器1.x。
彼得·阿勒斯 Peter Ahlers)

我喜欢使用history.back()<a href="javascript:history.back()" class="btn btn-default no-radius">
Serip88 '17

146

我使用resolve在移动到新状态之前保存当前状态数据:

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

8
比应付要好得多$stateChangeSuccess
SET

10
我认为,这应该是公认的答案。事件虽然可以$stateChangeSuccess奏效,但它是在全球范围内进行的,大多数时候并不需要。
Pierre Spring

2
我同意。这更干净。如果您要处理的所有模块都具有状态,则每个状态更改都会触发$ stateChangeSuccess,而不仅仅是模块中的状态更改。对此的另一个投票是更好的解决方案。
杰森·布坎南

1
@ Nissassin17您使用哪个版本?在v0.2.15中,当直接打开状态时,$state.currentis对象:{name: "", url: "^", views: null, abstract: true}
Endy Tjahjono

3
仅供参考-我需要执行以下操作:参数:angular.copy($ state.params)-说明:我正在使用UI-Router v 1.0.0-beta 2,并且此代码的​​Params部分存在问题;因为$ state.params是一个对象,所以在解析函数后它将更新到当前视图...我需要在resolve函数中执行此操作,以防止该对象在当前视图中被更新。
乔H

100

为了便于阅读,我将在这里放置我的解决方案(基于stu.salsbury的anwser)。

将此代码添加到应用程序的抽象模板中,以便在每个页面上运行。

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

跟踪rootScope的更改。它非常方便。


19
如果您真的想将某人重定向回他们来自的地方,那么也应该存储fromParams。
Yaron 2015年

我喜欢这个,并在我的应用程序中实现它。谢谢
Fallenreaper

真的很有用...使用localStorage甚至可以在任何地方获取previousState。
georgeos

14

在下面的示例中,我创建了一个decorator(在配置阶段每个应用仅运行一次),并向$state服务添加了一个额外的属性,因此该方法不会向,而不向其他服务添加全局变量,$rootscope也不需要向其添加任何额外的依赖项$state

在我的示例中,我需要在用户已经登录时以及在登录后不将其重定向到先前的“受保护”页面时将用户重定向到索引页面。

我使用的唯一未知服务(为您服务)是authenticationFactoryappSettings

  • authenticationFactory只需管理用户登录。在这种情况下,我仅使用一种方法来识别用户是否已登录。
  • appSettings是常量,只是为了不在任何地方使用字符串。appSettings.states.loginappSettings.states.register包含登录和注册网址的状态名称。

然后,在任何controller/ serviceetc中,您需要注入$state服务,并且可以像这样访问当前和以前的URL:

  • 当前: $state.current.name
  • 以前: $state.previous.route.name

在Chrome控制台中:

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

实现方式:

(我正在使用angular-ui-router v0.2.17angularjs 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);

12

在$ stateChangeStart的$ state中添加一个名为{previous}的新属性

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

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

现在您需要的任何地方都可以使用$ state,您将可以使用之前的状态

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

并像这样使用它:

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

9

我陷入同样的​​问题,并找到最简单的方法来做...

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

要么

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

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

(如果您希望它具有更高的可测试性,请将$ window服务注入您的控制器并使用$ window.history.back())。


当您在应用程序中有菜单时,情况会更加复杂
Swanand '17

没有得到您的问题,请提供更多详细信息
NiRmaL

如果不将其压入url,则会丢失$ stateParams,更好的解决方案是将以前的参数保存在$ rootScope中,您可以从中获取它,然后压入$ state以返回。
dangquang1020

这个答案对我来说最容易实现。
Lalnuntluanga Chhakchhuak

8

对于Endy Tjahjono,我使用类似的方法。

我要做的是在进行转换之前保存当前状态的值。让我们看一个例子;想象一下,在攀登到任何触发转换的函数中执行以下操作:

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

这里的关键是params对象(将发送到状态的参数的映射)-> { previousState : { name : $state.current.name } }

注意:请注意,我只“保存” $ state对象的name属性,因为这是我唯一需要保存的状态。但是我们可以拥有整个状态对象。

然后,状态“无论如何”的定义如下:

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

在这里,关键点是params对象。

params : {
  previousState: null,
}

然后,在该状态内,我们可以像这样获得先前的状态:

$state.params.previousState.name

6

这是来自Chris Thielen ui-router-extras的一个非常优雅的解决方案:$ previousState

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

previous是一个看起来像这样的对象:{ state: fromState, params: fromParams }其中fromState是先前的状态,fromParams是先前的状态参数。


1
2017年5月16日,克里斯·蒂伦(Chris Thielen)为该项目添加了使用寿命终止通知:ui-router-extras。
Michael R

4

好的,我知道我在这里参加聚会迟到了,但是我是新手。我正在尝试使其适合John Papa风格指南。我想使它可重用,所以我在一个代码块中创建了它。这是我想出的:

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

核心模块

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

对此代码的任何批评只会对我有所帮助,所以请让我知道我可以在哪里改进此代码。


2

如果您只需要此功能,并想在多个控制器中使用它,这是跟踪路线历史记录的一项简单服务:

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

.module('core')中的'core'将是您的应用程序/模块的名称。将服务作为对控制器的依赖项,然后可以在控制器中执行以下操作:$scope.routeHistory = RouterTracker.getRouteHistory()


4
如果我的页面上有一个导航按钮,它会转到历史记录中的先前状态,则导航到该先前状态后,将触发stateChangeSuccess并将其添加到历史记录中。那么,这段代码难道不会导致在2页之间来回循环吗?
whatsTheDiff

1

我在$ rootScope中跟踪以前的状态,因此只要有需要,我都将调用下面的代码行。

$state.go($rootScope.previousState);

App.js中

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

1
我认为最好不只是保存from.name。这样,如果需要执行类似$ state.go($ tootScope.previousState.name,$ tootScope.previousState.params)的操作,则也将具有参数。
abelabbesnabi

0

对于UI-Router(> = 1.0),不建议使用StateChange事件。有关完整的迁移指南,请单击此处

要在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');
    });
});

-1

一个非常简单的解决方案是编辑$ state.current.name字符串,并切掉所有内容,包括最后一个'和'。-您将获得父州的名称。如果您在状态之间跳了很多,这将不起作用,因为它只会解析当前路径。但是,如果您的状态与您实际所在的位置相对应,则此方法有效。

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

1
$state.go('^')会做到这一点
詹姆斯

那国家参数呢?
塔莎·舒克拉

-2

您可以通过以下方式返回状态:

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

一个例子:

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

    };

})();

2
如果要从非父状态访问状态,那不是一个好答案。如果您只想要当前状态的父级,那么它将完成此工作。
Maxime Lafarie '16

1
这与使用$ state.go(“ ^”)一样吗?
Nathan Moinvaziri '16
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.