如何从$ stateChangeStart访问UI-Router根状态的'resolve'属性?

时间:2022-06-03 12:18:25

I'm trying to implement a user auth check and access check system in my app, however I keep hitting roadblocks. I think I have it the correct way this time but I have one last hurdle.

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

A little background: I tried putting all of the code into the $rootScope.on($startChangeStart) and it worked, horribly... but it worked. The route was always redirected but due to the auth check on the backend it displayed the first request page for 1/2 a second and then the redirect page every time. Thus I tried 'pausing' page load by calling evt.preventDefault() right at the start of the $startChangeStart function, which worked, but trying to put the user back to the original route afterwards caused an infinite loop in the router.

一点背景:我尝试将所有代码放入$ rootScope.on($ startChangeStart)并且它工作得非常糟糕......但它确实有效。路由总是被重定向,但由于后端的auth检查,它显示第一个请求页面1/2秒,然后每次重定向页面。因此,我尝试通过在$ startChangeStart函数的开头调用evt.preventDefault()来“暂停”页面加载,这有效,但是尝试将用户放回到原始路由之后导致路由器中的无限循环。

So after more research and reading a lot of stack posts I'm certain that 'resolve:' is the proper place to put the auth check to ensure the page is not loading while it occurs, and then redirect the user if needed from the $startChangeStart. ($state and event are always undefined in my attempts to inject them into a resolve function) It seems like the winning combination.

因此,经过更多的研究和阅读大量的帖子后,我确信'resolve:'是进行auth检查的正确位置,以确保页面在发生时不加载,然后根据需要从$重定向用户startChangeStart。 ($状态和事件在我尝试将它们注入解析函数时总是未定义的)这似乎是获胜的组合。

My problem: I have the resolve on the root state in my app: 'main'

我的问题:我对我的应用中的root状态有了决心:'main'

This was to avoid code redundancy, however I cannot determine how to access the root state's properties, and therefore the resolve result, from the $stateChangeStart function. The toState is the child state, while the fromState is either the previous state or an abstract state with the '^' route...

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

Do I have to put the resolve on every child state for this to work, or is there a way to access the root state from this point?

我是否必须将解决方案放在每个子状态才能使用,或者是否有办法从此处访问根状态?

Basic app setup:

基本应用设置:

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

This is the output from the console.dir() calls on the two state objects:

这是对两个状态对象的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

Update

更新

Oops, forgot to mention AngularJS version is v1.2.0-rc.2

哎呀,忘了提一下AngularJS版本是v1.2.0-rc.2

$state.current console.dir()

$ state.current console.dir()

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

5 个解决方案

#1


8  

Yes, I believe you can access root state from the $stateChangeStart function.

是的,我相信你可以从$ stateChangeStart函数访问root状态。

When using pure AngularJS I normally use current.$$route

当使用纯AngularJS时,我通常使用当前的。$$路由

For example, using the following route

例如,使用以下路线

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

I can access the root state like so

我可以像这样访问root状态

  $rootScope.$on('$routeChangeSuccess', function (event, current, previous) {

   if (current.$$route) {

     $rootScope.title      = current.$$route.title;

     $rootScope.bodyClass  = current.$$route.bodyClass;
   }

 });

Using ui-router it's just a bit different as it's called $state.current. And you can access all the properties associated to whatever route you hit (e.g: $state.current.url)

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

So on your code you could have something like this

所以在你的代码上你可以得到类似的东西

  .run(['$rootScope', '$state', '$stateParams', function ($rootScope, $state, $stateParams) {

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

#2


1  

You need not to use resolve. Take a look at my solution:

你不需要使用解决方案。看看我的解决方案:

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

I use angular_devise and ngDialog but they are optional and you can implement it with your own user's service.

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

#3


0  

Is it possible to do the redirect from within your accountService? If you detect that the user fails your checkAuth or checkAccess functions, you could prevent the callback from executing and redirect the user to your error (or login) page.

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

Something else to consider is implementing some sort of variable/queue of states if you'd like to redirect someone to the login page to refresh their authorization/authentication and then return to the previous state.

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

#4


0  

If you initialize your state with a default, empty object on resolve, you'll be able to manipulate it within $stateChangeStart.

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

$stateProvider
  .state 'home',
    url: "/"
    resolve: {}

...

  $rootScope.$on '$stateChangeStart', (e, toState, toParams, fromState, fromParams) ->
    toState.resolve.x = ->
      $timeout ->
        alert "done"
      , 3000

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

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

#5


0  

This answer is very late but it can be useful.

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

Resolves of a state and $stateChangeStart event are executed at the same time. By the time you try to access resolved data in $stateChangeStart, it'll not be available but it'll be available when $stateChangeSuccess event fires.

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

If you use $stateChangeStart then you'll need to do checkAuth from two places $stateChangeStart event and main resolve. Since they have parallel execution, at least 2 network requests will be sent to server for the same data.

如果你使用$ stateChangeStart,那么你需要从两个地方进行checkAuth $ stateChangeStart事件和主要解析。由于它们具有并行执行功能,因此将向服务器发送至少2个网络请求以获取相同的数据。

Instead use $stateChangeSuccess. Using this will ensure that your resolves are resolved and you can then check access. Also, instead of accessing resolved properties,access resolved data using angular service.

而是使用$ stateChangeSuccess。使用此选项可确保您的结算已解决,然后您可以检查访问权限。此外,不使用已解析的属性,而是使用角度服务访问已解析的数据。

#1


8  

Yes, I believe you can access root state from the $stateChangeStart function.

是的,我相信你可以从$ stateChangeStart函数访问root状态。

When using pure AngularJS I normally use current.$$route

当使用纯AngularJS时,我通常使用当前的。$$路由

For example, using the following route

例如,使用以下路线

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

I can access the root state like so

我可以像这样访问root状态

  $rootScope.$on('$routeChangeSuccess', function (event, current, previous) {

   if (current.$$route) {

     $rootScope.title      = current.$$route.title;

     $rootScope.bodyClass  = current.$$route.bodyClass;
   }

 });

Using ui-router it's just a bit different as it's called $state.current. And you can access all the properties associated to whatever route you hit (e.g: $state.current.url)

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

So on your code you could have something like this

所以在你的代码上你可以得到类似的东西

  .run(['$rootScope', '$state', '$stateParams', function ($rootScope, $state, $stateParams) {

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

#2


1  

You need not to use resolve. Take a look at my solution:

你不需要使用解决方案。看看我的解决方案:

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

I use angular_devise and ngDialog but they are optional and you can implement it with your own user's service.

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

#3


0  

Is it possible to do the redirect from within your accountService? If you detect that the user fails your checkAuth or checkAccess functions, you could prevent the callback from executing and redirect the user to your error (or login) page.

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

Something else to consider is implementing some sort of variable/queue of states if you'd like to redirect someone to the login page to refresh their authorization/authentication and then return to the previous state.

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

#4


0  

If you initialize your state with a default, empty object on resolve, you'll be able to manipulate it within $stateChangeStart.

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

$stateProvider
  .state 'home',
    url: "/"
    resolve: {}

...

  $rootScope.$on '$stateChangeStart', (e, toState, toParams, fromState, fromParams) ->
    toState.resolve.x = ->
      $timeout ->
        alert "done"
      , 3000

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

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

#5


0  

This answer is very late but it can be useful.

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

Resolves of a state and $stateChangeStart event are executed at the same time. By the time you try to access resolved data in $stateChangeStart, it'll not be available but it'll be available when $stateChangeSuccess event fires.

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

If you use $stateChangeStart then you'll need to do checkAuth from two places $stateChangeStart event and main resolve. Since they have parallel execution, at least 2 network requests will be sent to server for the same data.

如果你使用$ stateChangeStart,那么你需要从两个地方进行checkAuth $ stateChangeStart事件和主要解析。由于它们具有并行执行功能,因此将向服务器发送至少2个网络请求以获取相同的数据。

Instead use $stateChangeSuccess. Using this will ensure that your resolves are resolved and you can then check access. Also, instead of accessing resolved properties,access resolved data using angular service.

而是使用$ stateChangeSuccess。使用此选项可确保您的结算已解决,然后您可以检查访问权限。此外,不使用已解析的属性,而是使用角度服务访问已解析的数据。