2013-10-02 19 views
17

我試圖在我的應用程序中實現用戶身份驗證檢查和訪問檢查系統,但是我一直在碰到障礙。我認爲這次我擁有正確的方式,但我還有最後一個障礙。我試着把所有的代碼都放到$ rootScope.on($ startChangeStart)中,它的工作,非常可怕......但它工作。該路由總是被重定向,但由於後端的auth檢查,它顯示第一個請求頁面1/2秒,然後每次顯示重定向頁面。因此,我試圖在$ startChangeStart函數的開始處調用evt.preventDefault()來「暫停」頁面加載,該函數工作正常,但試圖讓用戶回到原來的路由之後導致路由器中的無限循環。

因此,經過更多的研究和閱讀大量的帖子帖子,我確定'resolve:'是放置auth檢查以確保頁面在加載時不加載的適當位置,然後重定向用戶if需要從$ startChangeStart。 ($ state和event總是未定義的,我嘗試將它們注入到resolve函數中)這看起來像是獲勝的組合。

我的問題:我有我的應用程序的根狀態的決心:「主」

這是爲了避免代碼冗餘,但我不能確定如何訪問根狀態的屬性,因此決心結果,從$ 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 

回答

7

是的,我相信你可以從$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)

所以在你的代碼,你可以有你的accountService內像這樣

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

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

我剛剛在$ stateChangeStart中的$ state.current對象上做了一個console.dir,現在它被添加了。這是一個抽象的對象。如果我將工作移動到另一個函數中並使用$ state,那麼$ state就是子對象..但是應該有一種方法可以在不爲函數創建額外行的情況下訪問它...不是? 此外,這仍然不允許我訪問根狀態,其中包含解決方案。 – Routhinator

+1

您是否最終搞清楚如何從stateChangeStart中訪問解析數據? – Yavar

+2

我的印象是解析數據在stateChangeStart事件後被「解決」了......即。如果你調用'event.preventDefault()',那麼結果永遠不會開始。但我可能是錯的。 –

0

是否有可能從做重定向?如果您檢測到用戶未能通過checkAuth或checkAccess功能,則可能會阻止執行回調,並將用戶重定向到錯誤(或登錄)頁面。

如果您想將某人重定向到登錄頁面以刷新其授權/身份驗證,然後返回到以前的狀態,則需要考慮的其他事情是實施某種變量/隊列狀態。

1

您不需要使用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但它們是可選的,你可以用自己的用戶服務實現它。

0

如果您使用默認的空白對象初始化您的狀態,您將能夠在$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

0

這個答案是非常晚,但它可能是有用的。

解決狀態和$stateChangeStart事件是在同一時間執行的。當您嘗試訪問$stateChangeStart中已解析的數據時,它將無法使用,但在事件觸發時它將可用。

如果您使用$stateChangeStart那麼您需要從$stateChangeStart兩個地方做checkAuth事件和主要解決方案。由於它們具有並行執行能力,因此至少有兩個網絡請求將被髮送到服務器以獲取相同的數據。

改爲使用$stateChangeSuccess。使用這將確保您的解決方案已解決,然後您可以檢查訪問權限。此外,不是訪問已解析的屬性,而是使用角度服務訪問解析的數據。