角ui-路由器获得先前状态

时间:2021-08-31 11:02:32

Is there a way to get the previous state of the current state?

有没有一种方法可以得到当前状态的前一状态?

For example I would like to know what the previous state was before current state B (where previous state would have been state A).

例如,我想知道当前状态B之前的前一个状态是什么(其中前一个状态应该是状态A)。

I am not able to find it in ui-router github doc pages.

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

13 个解决方案

#1


128  

ui-router doesn't track the previous state once it transitions, but the event $stateChangeSuccess is broadcast on the $rootScope when the state changes.

ui-router在转换后不会跟踪先前的状态,但是当状态发生变化时,事件$stateChangeSuccess会在$rootScope上进行广播。

You should be able to catch the prior state from that event (from is the state you're leaving):

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

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

#2


135  

I use resolve to save the current state data before moving to the new state:

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

#3


94  

For sake of readability, I'll place my solution (based of stu.salsbury's anwser) here.

为了便于阅读,我将基于stu提出我的解决方案。这里salsbury回答)。

Add this code to your app's abstract template so it runs on every page.

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

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

Keeps track of the changes in rootScope. Its pretty handy.

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

#4


14  

In the following example i created a decorator (runs only once per app at configuration phase) and adds an extra property to $state service, so this approach does not add global variables to $rootscope and does not require to add any extra dependency to other services than $state.

在下面的示例中,我创建了一个decorator(在配置阶段每个应用程序只运行一次),并向$state服务添加了一个额外的属性,因此这种方法不向$rootscope添加全局变量,并且不需要向其他服务添加除$state之外的任何附加依赖项。

In my example i needed to redirect a user to the index page when he was already signed in and when he was not to redirect him to the previous "protected" page after sign in.

在我的示例中,我需要在用户已经登录并没有将其重定向到之前的“受保护”页面时将其重定向到索引页面。

The only unknown services (for you) that i use are authenticationFactory and appSettings:

我使用的惟一未知服务是authenticationFactory和appSettings:

  • authenticationFactory just administrates the user login. In this case i use only a method to identify if the user is logged in or not.
  • authenticationFactory只是管理用户登录。在这种情况下,我只使用一个方法来识别用户是否登录。
  • appSettings are constants just for not use strings everywhere. appSettings.states.login and appSettings.states.register contain the name of the state for the login and register url.
  • appSettings是常量,因为它不会在任何地方使用字符串。appSettings.states。登录和appSettings.states。寄存器包含登录和注册url的状态的名称。

Then in any controller/service etc you need to inject $state service and you can access current and previous url like this:

然后在任何控制器/服务等,你需要注入$state服务,你可以访问当前和以前的url如下:

  • Current: $state.current.name
  • 当前:$ state.current.name
  • Previous: $state.previous.route.name
  • 前一:$ state.previous.route.name

From the Chrome console:

从Chrome控制台:

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

Implementation:

实现:

(I'm using angular-ui-router v0.2.17 and angularjs v1.4.9)

(我使用的是angular-ui-router v0.2.17和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);

#5


10  

Add a new property called {previous} to $state on $stateChangeStart

在$stateChangeStart上向$state添加一个名为{before}的新属性

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

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

Now anywhere you need can use $state you will have previous available

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

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

And use it like so:

像这样使用它:

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

#6


7  

I use a similar approach to what Endy Tjahjono does.

我对恩迪·塔哈约诺的做法也有类似的做法。

What I do is to save the value of the current state before making a transition. Lets see on an example; imagine this inside a function executed when cliking to whatever triggers the transition:

我所做的是在进行转换之前保存当前状态的值。让我们看一个例子;想象一下,在一个函数中,当剪切到触发转换的任何东西时,会发生以下情况:

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

The key here is the params object (a map of the parameters that will be sent to the state) -> { previousState : { name : $state.current.name } }

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

Note: note that Im only "saving" the name attribute of the $state object, because is the only thing I need for save the state. But we could have the whole state object.

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

Then, state "whatever" got defined like this:

然后,状态“whatever”的定义如下:

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

Here, the key point is the params object.

这里的关键点是params对象。

params : {
  previousState: null,
}

Then, inside that state, we can get the previous state like this:

然后,在这个状态下,我们可以得到先前的状态

$state.params.previousState.name

#7


6  

Here is a really elegant solution from Chris Thielen ui-router-extras: $previousState

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

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

previous is an object that looks like: { state: fromState, params: fromParams } where fromState is the previous state and fromParams is the previous state parameters.

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

#8


6  

I am stuck with same issue and find the easiest way to do this...

我遇到了同样的问题,找到了最简单的解决方法……

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

(If you want it to be more testable, inject the $window service into your controller and use $window.history.back()).

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

#9


4  

Ok, I know that I am late to the party here, but I am new to angular. I am trying to make this fit into the John Papa style guide here. I wanted to make this reusable so I created in a block. Here is what I came up with:

好吧,我知道我去参加派对晚了,但我对角度还不太熟悉。我正试着让它融入约翰爸爸的风格指南。我想让它可重用,所以我创建了一个块。以下是我的想法:

previousStateProvider

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

core.module

(function () {
'use strict';

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

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

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

core.config

core.config

(function () {
'use strict';

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

core.run(appRun);

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

Any critique on this code will only help me, so please let me know where I can improve this code.

对这段代码的任何批评都只会对我有帮助,所以请告诉我在哪里可以改进这段代码。

#10


2  

If you just need this functionality and want to use it in more than one controller, this is a simple service to track route history:

如果您只需要这个功能,并希望在多个控制器中使用它,那么这是一个跟踪路由历史的简单服务:

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

where the 'core' in .module('core') would be the name of your app/module. Require the service as a dependency to your controller, then in your controller you can do: $scope.routeHistory = RouterTracker.getRouteHistory()

在.module(“core”)中的“核心”将是应用程序/模块的名称。需要将服务作为控制器的依赖项,然后在控制器中可以做:$scope。routeHistory = RouterTracker.getRouteHistory()

#11


0  

A really simple solution is just to edit the $state.current.name string and cut out everything including and after the last '.' - you get the name of the parent state. This doesn't work if you jump a lot between states because it just parses back the current path. But if your states correspond to where you actually are, then this works.

一个非常简单的解决方案就是编辑$state.current.name字符串,并删除所有内容,包括最后一个。-你得到父国家的名字。如果你在不同的状态间跳转很多次,这将不起作用,因为它只解析当前路径。但是如果你的状态对应于你实际所在的位置,那么这个是可行的。

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

#12


0  

I keep track of previous states in $rootScope, so whenever in need I will just call the below line of code.

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

$state.go($rootScope.previousState);

In App.js:

在App.js:

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

#13


-2  

You can return the state this way:

您可以这样返回状态:

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

An example:

一个例子:

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

    };

})();

#1


128  

ui-router doesn't track the previous state once it transitions, but the event $stateChangeSuccess is broadcast on the $rootScope when the state changes.

ui-router在转换后不会跟踪先前的状态,但是当状态发生变化时,事件$stateChangeSuccess会在$rootScope上进行广播。

You should be able to catch the prior state from that event (from is the state you're leaving):

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

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

#2


135  

I use resolve to save the current state data before moving to the new state:

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

#3


94  

For sake of readability, I'll place my solution (based of stu.salsbury's anwser) here.

为了便于阅读,我将基于stu提出我的解决方案。这里salsbury回答)。

Add this code to your app's abstract template so it runs on every page.

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

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

Keeps track of the changes in rootScope. Its pretty handy.

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

#4


14  

In the following example i created a decorator (runs only once per app at configuration phase) and adds an extra property to $state service, so this approach does not add global variables to $rootscope and does not require to add any extra dependency to other services than $state.

在下面的示例中,我创建了一个decorator(在配置阶段每个应用程序只运行一次),并向$state服务添加了一个额外的属性,因此这种方法不向$rootscope添加全局变量,并且不需要向其他服务添加除$state之外的任何附加依赖项。

In my example i needed to redirect a user to the index page when he was already signed in and when he was not to redirect him to the previous "protected" page after sign in.

在我的示例中,我需要在用户已经登录并没有将其重定向到之前的“受保护”页面时将其重定向到索引页面。

The only unknown services (for you) that i use are authenticationFactory and appSettings:

我使用的惟一未知服务是authenticationFactory和appSettings:

  • authenticationFactory just administrates the user login. In this case i use only a method to identify if the user is logged in or not.
  • authenticationFactory只是管理用户登录。在这种情况下,我只使用一个方法来识别用户是否登录。
  • appSettings are constants just for not use strings everywhere. appSettings.states.login and appSettings.states.register contain the name of the state for the login and register url.
  • appSettings是常量,因为它不会在任何地方使用字符串。appSettings.states。登录和appSettings.states。寄存器包含登录和注册url的状态的名称。

Then in any controller/service etc you need to inject $state service and you can access current and previous url like this:

然后在任何控制器/服务等,你需要注入$state服务,你可以访问当前和以前的url如下:

  • Current: $state.current.name
  • 当前:$ state.current.name
  • Previous: $state.previous.route.name
  • 前一:$ state.previous.route.name

From the Chrome console:

从Chrome控制台:

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

Implementation:

实现:

(I'm using angular-ui-router v0.2.17 and angularjs v1.4.9)

(我使用的是angular-ui-router v0.2.17和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);

#5


10  

Add a new property called {previous} to $state on $stateChangeStart

在$stateChangeStart上向$state添加一个名为{before}的新属性

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

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

Now anywhere you need can use $state you will have previous available

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

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

And use it like so:

像这样使用它:

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

#6


7  

I use a similar approach to what Endy Tjahjono does.

我对恩迪·塔哈约诺的做法也有类似的做法。

What I do is to save the value of the current state before making a transition. Lets see on an example; imagine this inside a function executed when cliking to whatever triggers the transition:

我所做的是在进行转换之前保存当前状态的值。让我们看一个例子;想象一下,在一个函数中,当剪切到触发转换的任何东西时,会发生以下情况:

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

The key here is the params object (a map of the parameters that will be sent to the state) -> { previousState : { name : $state.current.name } }

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

Note: note that Im only "saving" the name attribute of the $state object, because is the only thing I need for save the state. But we could have the whole state object.

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

Then, state "whatever" got defined like this:

然后,状态“whatever”的定义如下:

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

Here, the key point is the params object.

这里的关键点是params对象。

params : {
  previousState: null,
}

Then, inside that state, we can get the previous state like this:

然后,在这个状态下,我们可以得到先前的状态

$state.params.previousState.name

#7


6  

Here is a really elegant solution from Chris Thielen ui-router-extras: $previousState

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

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

previous is an object that looks like: { state: fromState, params: fromParams } where fromState is the previous state and fromParams is the previous state parameters.

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

#8


6  

I am stuck with same issue and find the easiest way to do this...

我遇到了同样的问题,找到了最简单的解决方法……

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

(If you want it to be more testable, inject the $window service into your controller and use $window.history.back()).

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

#9


4  

Ok, I know that I am late to the party here, but I am new to angular. I am trying to make this fit into the John Papa style guide here. I wanted to make this reusable so I created in a block. Here is what I came up with:

好吧,我知道我去参加派对晚了,但我对角度还不太熟悉。我正试着让它融入约翰爸爸的风格指南。我想让它可重用,所以我创建了一个块。以下是我的想法:

previousStateProvider

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

core.module

(function () {
'use strict';

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

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

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

core.config

core.config

(function () {
'use strict';

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

core.run(appRun);

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

Any critique on this code will only help me, so please let me know where I can improve this code.

对这段代码的任何批评都只会对我有帮助,所以请告诉我在哪里可以改进这段代码。

#10


2  

If you just need this functionality and want to use it in more than one controller, this is a simple service to track route history:

如果您只需要这个功能,并希望在多个控制器中使用它,那么这是一个跟踪路由历史的简单服务:

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

where the 'core' in .module('core') would be the name of your app/module. Require the service as a dependency to your controller, then in your controller you can do: $scope.routeHistory = RouterTracker.getRouteHistory()

在.module(“core”)中的“核心”将是应用程序/模块的名称。需要将服务作为控制器的依赖项,然后在控制器中可以做:$scope。routeHistory = RouterTracker.getRouteHistory()

#11


0  

A really simple solution is just to edit the $state.current.name string and cut out everything including and after the last '.' - you get the name of the parent state. This doesn't work if you jump a lot between states because it just parses back the current path. But if your states correspond to where you actually are, then this works.

一个非常简单的解决方案就是编辑$state.current.name字符串,并删除所有内容,包括最后一个。-你得到父国家的名字。如果你在不同的状态间跳转很多次,这将不起作用,因为它只解析当前路径。但是如果你的状态对应于你实际所在的位置,那么这个是可行的。

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

#12


0  

I keep track of previous states in $rootScope, so whenever in need I will just call the below line of code.

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

$state.go($rootScope.previousState);

In App.js:

在App.js:

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

#13


-2  

You can return the state this way:

您可以这样返回状态:

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

An example:

一个例子:

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

    };

})();