Angular - ui-router 获取先前的状态

Posted

技术标签:

【中文标题】Angular - ui-router 获取先前的状态【英文标题】:Angular - ui-router get previous state 【发布时间】:2013-05-14 04:14:11 【问题描述】:

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

例如,我想知道在当前状态 B 之前的先前状态是什么(先前的状态应该是状态 A)。

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

【问题讨论】:

下面的答案是正确的,如果文档没有足够的帮助goo.gl/9B9bH,您还可以从源代码中找到您需要的所有信息 【参考方案1】:

我在移动到新状态之前使用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: angular.copy($state.params),
                        URL: $state.href($state.current.name, $state.params)
                    ;
                    return currentStateData;
                ]
            
        );
]);

【讨论】:

比处理$stateChangeSuccess好多了 在我看来,这应该是公认的答案。事件虽然$stateChangeSuccess 有效,但它是在全球范围内完成的,大部分时间并不真正需要。 我同意。这干净多了。如果您正在处理许多都有状态的模块,则 $stateChangeSuccess 将在每次状态更改时触发,而不仅仅是模块中的那些。另一票认为这是更好的解决方案。 @Nissassin17 你用的是哪个版本?在 v0.2.15 中直接打开状态时,$state.current 是对象:name: "", url: "^", views: null, abstract: true 仅供参考 - 我需要执行以下操作: 参数:angular.copy($state.params) - 说明:我正在使用 UI-Router v 1.0.0-beta 2,但我遇到了问题使用此代码的 Params 部分;因为 $state.params 是一个对象,它会在函数解析后更新到当前视图...我需要在解析函数中执行此操作以防止对象在当前视图中更新。【参考方案2】:

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

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

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

【讨论】:

使用“from”的例子是什么? 这里的“to”和“from”表示“toState”和“fromState”。考虑您之前的 url 是 localhost:xxxx/employee 并且控制器是 'EmployeesController' 那么 'fromState' 的示例是: Object url: "/employees", templateUrl: "/employees", controller: "EmployeesController", name: "员工” 我在摘要中这样做了:` $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 中的先前和当前。很方便! 使用@endy-tjahjono (***.com/a/25945003/2837519) 的解决方案更加内联ui-router 1.x。 我喜欢简单的 history.back() 【参考方案3】:

为了便于阅读,我将把我的解决方案(基于 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 中的更改。它非常方便。

【讨论】:

如果您真的想将某人重定向回他们来自的地方,那么存储 fromParams 也是值得的。 我喜欢这个并在我的应用程序中实现它。谢谢 真的很有用...更使用localStorage,可以在任何地方获取previousState。【参考方案4】:

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

在我的示例中,当用户已经登录时,我需要将用户重定向到索引页面,并且当他不希望在登录后将他重定向到上一个“受保护”页面时。

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

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

然后在任何controller/service 等中,您需要注入$state 服务,您可以像这样访问当前和以前的网址:

当前:$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);

【讨论】:

【参考方案5】:

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

【讨论】:

【参考方案6】:

我遇到了同样的问题,并找到了最简单的方法......

//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())。

【讨论】:

应用程序中有菜单时会更复杂 没有遇到您的问题,请提供更多详细信息 如果不将 $stateParams 推送到 url,您将丢失它,更好的解决方案是将以前的参数保存在 $rootScope 中,您可以从中获取并推送到 $state 以返回。 这个答案对我来说最容易实现。【参考方案7】:

我使用与 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

【讨论】:

【参考方案8】:

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

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

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

【讨论】:

2017 年 5 月 16 日,Chris Thielen 为该项目添加了 End of Life Notice:ui-router-extras。【参考方案9】:

好的,我知道我在这里聚会迟到了,但我是 Angular 新手。我正在尝试使其适合 John Papa style guide 此处。我想让它可重用,所以我在一个块中创建。这是我想出的:

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

)();

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

【讨论】:

【参考方案10】:

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

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

【讨论】:

如果我的页面上有一个导航按钮可以转到历史记录中的前一个状态,在导航到该前一个状态后,将触发 stateChangeSuccess 并将其添加到历史记录中。那么这段代码不会导致在两页之间来回循环吗?【参考方案11】:

我会在 $rootScope 中跟踪以前的状态,所以只要有需要,我就会调用下面的代码行。

$state.go($rootScope.previousState);

App.js 中:

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

【讨论】:

我认为如果你不只是从 from.name 保存会更好。这样,您也将拥有参数,以防您需要执行类似 $state.go($tootScope.previousState.name, $tootScope.previousState.params);【参考方案12】:

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

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

【讨论】:

$state.go('^') 将完成此操作 状态参数呢?【参考方案13】:

对于 UI-Router(>=1.0),StateChange 事件已被弃用。 如需完整的迁移指南,请点击here

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

【讨论】:

【参考方案14】:

你可以这样返回状态:

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

    ;

)();

【讨论】:

如果您从非父状态访问状态,这不是一个好的答案。如果您只想要当前状态的父级,它就可以完成工作。 这不是和使用 $state.go("^") 一样吗?

以上是关于Angular - ui-router 获取先前的状态的主要内容,如果未能解决你的问题,请参考以下文章

angular ui-router:在解析中获取 toState 的 $state 信息

Angular UI-Router,在 URL 刷新时找不到 [重复]

ngRoute (angular-route.js) 和 ui-router (angular-ui-router.js) 模块有什么不同呢?

Angular 1.5,ui-router + 资源 + 组件,stateProvider 找不到组件

Angular单页应用&AngularJS内部实现原理

带有angular1.5组件meteor和ui-router的动态标题