【问题标题】:How do I access the 'resolve' property of a UI-Router root state from $stateChangeStart?如何从 $stateChangeStart 访问 UI-Router 根状态的“解析”属性?
【发布时间】:2013-10-02 16:17:26
【问题描述】:

我正在尝试在我的应用程序中实现用户身份验证检查和访问检查系统,但是我一直遇到障碍。我想这次我的方法是正确的,但我还有最后一个障碍。

一点背景知识:我尝试将所有代码放入 $rootScope.on($startChangeStart) 并且它工作,可怕......但它工作。该路由始终被重定向,但由于后端的身份验证检查,它以每秒 1/2 的速度显示第一个请求页面,然后每次都显示重定向页面。因此,我尝试通过在 $startChangeStart 函数开始时调用 evt.preventDefault() 来“暂停”页面加载,该函数有效,但随后试图将用户放回原始路由会导致路由器中的无限循环。

因此,经过更多研究和阅读大量堆栈帖子后,我确信“解决:”是进行身份验证检查以确保页面在发生时不会加载的正确位置,然后在需要时重定向用户从 $startChangeStart。 (在我尝试将 $state 和 event 注入 resolve 函数时,它们总是未定义)这似乎是成功的组合。

我的问题:我已经解决了我的应用程序中的根状态:'main'

这是为了避免代码冗余,但是我无法确定如何从 $stateChangeStart 函数访问根状态的属性以及解析结果。 toState 是子状态,而 fromState 是前一个状态或带有 '^' 路由的抽象状态...

我是否必须对每个子状态都进行解析才能使其正常工作,还是有办法从此时访问根状态?

基本应用设置:

angular.module('App', ['ui.router', 'ui.bootstrap', 'ui.event', 'AngularGM', 'ngResource'])
.config(['$urlRouterProvider', '$stateProvider', function($urlRouterProvider, $stateProvider){
    $urlRouterProvider
        .when('/home', '/')
        .when('', '/')
        .when('/sign-up/joe', '/sign-up')
        .otherwise('/');

    $stateProvider
        .state('main', {
            url: '',
            abstract: true,
            templateUrl: 'views/main.html',
            controller: 'MainCtrl',
            resolve: {
                checkAccess: ['accountService', function(accountService) {
                    accountService.checkAuth(function(){
                        accountService.checkAccess(function (access){
                            return access;
                        });
                    });
                }]
            }
        })
        .state('main.home', {
            url: '',
            abstract: true,
            templateUrl: 'views/home.html',
            controller: 'HomeCtrl'
        })
        .state('main.home.index', {
            url: '/',
            templateUrl: 'views/home/index.html'
        });


.run(['$rootScope', '$state', '$stateParams', 'accountService', function ($rootScope, $state, $stateParams) {
    $rootScope.$state = $state;
    $rootScope.$stateParams = $stateParams;
    $rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams) {
        console.dir(toState);
        console.dir(toParams);
        console.dir(fromState);
        console.dir(fromParams);
        if (!toState.checkAccess.allowed) {
            event.preventDefault();
            $state.transitionTo(toState.checkAccess.newState);
        }
    });
}]);

这是 console.dir() 调用两个状态对象的输出:

Object
 name: "main.home.index"
 templateUrl: "views/home/index.html"
 url: "/"
 __proto__: Object

Object
 controller: "PlacesCtrl"
 name: "main.places.search"
 templateUrl: "views/places.html"
 url: "/places"
 __proto__: Object

更新

哎呀,忘了说AngularJS版本是v1.2.0-rc.2

$state.current console.dir()

Object
 abstract: true
 name: ""
 url: "^"
 views: null
 __proto__: Object

【问题讨论】:

    标签: angularjs angular-ui-router


    【解决方案1】:

    是的,我相信您可以通过$stateChangeStart 函数访问根状态。

    在使用纯 AngularJS 时,我通常使用 current.$$route

    例如使用下面的路由

    .when('/home', {
      title:'Home',
      bodyClass: 'meetings',
      controler: 'HomeCtrl'
    })
    

    我可以像这样访问根状态

      $rootScope.$on('$routeChangeSuccess', function (event, current, previous) {
    
       if (current.$$route) {
    
         $rootScope.title      = current.$$route.title;
    
         $rootScope.bodyClass  = current.$$route.bodyClass;
       }
    
     });
    

    使用ui-router 只是有点不同,因为它被称为$state.current。您可以访问与您点击的任何路线相关的所有属性(例如:$state.current.url)

    所以在你的代码上你可以有这样的东西

      .run(['$rootScope', '$state', '$stateParams', function ($rootScope, $state, $stateParams) {
    
          $rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams) {
              console.log($state.current.url);
          });
      }]);
    

    【讨论】:

    • 我刚刚在 $stateChangeStart 中的 $state.current 对象上做了一个 console.dir,现在它被添加了。这是一个抽象的对象。如果我将工作移到另一个函数中并在其中使用 $state ,则 $state 是子对象..但是应该有一种方法可以访问它而无需为函数创建额外的行...不是吗?此外,这仍然不允许我访问包含解析的根状态。
    • 您是否最终弄清楚如何从 stateChangeStart 中访问解析数据?
    • 我的印象是在 stateChangeStart 事件之后解析数据被“解析”了......即。如果你打电话给event.preventDefault() 那么结果永远不会开始。不过我可能错了。
    • @RhysvanderWaerden,你是对的。 resolve 将在 stateChangeStart 之后触发,如果您正在寻找您的 resolve 以加载您的访问权限,例如页面刷新,则为时已晚。我正在寻找这个问题的解决方案。
    • 糟糕,按 Enter 太快了。无论如何,我这样做的方法是在权限不够的情况下在解析函数中抛出异常(如果是 400 错误,你可能会得到一个错误,如果它是一个 'isLoggedIn' 类型的查询,你可以抛出你自己)。然后我在$stateChangeError 中捕捉到这个并转发到相应的页面。
    【解决方案2】:

    您不必使用resolve。看看我的解决方案:

    app.run ($rootScope, $state, Auth, ngDialog) ->
      $rootScope.$on '$stateChangeStart', (e, to) ->
        if to.authRequired and not Auth.isAuthenticated()
          e.preventDefault()
          Auth.currentUser().then(
            (user) ->
              $state.go(to)
            (failure) ->
              $rootScope.storedState = to
              $state.go('main')
              ngDialog.closeAll()
              ngDialog.open
                template: 'modals/login.html'
                controller: 'loginCtrl'
                className: 'ngdialog-theme-default'
          )
    

    我使用angular_devisengDialog,但它们是可选的,您可以使用自己的用户服务来实现它。

    【讨论】:

      【解决方案3】:

      是否可以从您的accountService 中进行重定向?如果您检测到用户未通过您的 checkAuth 或 checkAccess 功能,您可以阻止回调执行并将用户重定向到您的错误(或登录)页面。

      如果您想将某人重定向到登录页面以刷新他们的授权/身份验证然后返回到之前的状态,则需要考虑的其他事情是实现某种变量/状态队列。

      【讨论】:

        【解决方案4】:

        如果您在解析时使用默认的空对象初始化您的状态,您将能够在$stateChangeStart 中对其进行操作。

        $stateProvider
          .state 'home',
            url: "/"
            resolve: {}
        
        ...
        
          $rootScope.$on '$stateChangeStart', (e, toState, toParams, fromState, fromParams) ->
            toState.resolve.x = ->
              $timeout ->
                alert "done"
              , 3000
        

        https://github.com/angular-ui/ui-router/issues/1165

        【讨论】:

          【解决方案5】:

          这个答案很晚,但它可能很有用。

          状态的解析和$stateChangeStart 事件同时执行。当您尝试访问 $stateChangeStart 中的已解析数据时,它将不可用,但在 $stateChangeSuccess 事件触发时将可用。

          如果您使用$stateChangeStart,那么您需要在两个地方执行checkAuth $stateChangeStart 事件和主要解析。由于它们是并行执行的,对于相同的数据,至少会向服务器发送 2 个网络请求。

          改为使用$stateChangeSuccess。使用这将确保您的解析得到解决,然后您可以检查访问权限。此外,不要访问已解析的属性,而是使用 Angular 服务访问已解析的数据。

          【讨论】:

            猜你喜欢
            • 2015-06-12
            • 1970-01-01
            • 2015-07-05
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多