2014-01-28 85 views
8

兩個問題已經困擾我,因爲我已經學會角:如何處理清爽頁面與AngularJS單頁應用

  1. 如何恢復狀態,當用戶刷新頁面或者點擊後退按鈕?

  2. 如何在屬於不同控制器的範圍之間共享數據?

下面我展示了一個使用客戶端會話存儲的簡單解決方案。它允許共同兩個數據共享和狀態自動恢復用戶刷新頁面或者點擊後退按鈕後。

注意:下面的方案就證明了必須回答以下問題:

How do I get the Back Button to work with an AngularJS ui-router state machine?

回答

5

的解決方案取決於如下所示的SessionService類。語法是coffeescript。

SessionService類

class SessionService 
    scopes:[] 

    setStorage:(key, value) -> 
     scope[key] = value for scope in @scopes 
     value = if value is undefined then null else JSON.stringify value 
     sessionStorage.setItem key, value 

    getStorage:(key)-> 
     sessionValue = sessionStorage.getItem key 
     if sessionValue == "undefined" 
      return null 
     JSON.parse sessionValue 

    register:(scope)-> 
     for key, value of sessionStorage 
      scope[key] = if value? and value != "undefined" then JSON.parse(value) else null 
     @scopes.push scope 
     scope.$on '$destroy', => 
      @scopes = @scopes.filter (s) -> s.$id != scope.$id 

    clear: -> 
     @setStorage(key, null) for key of sessionStorage 

    isAuthenticated: -> 
     @accessor 'isAuthenticated', value 

    user:(value=null) -> 
     @accessor 'user', value 

    # other storage items go here 

    accessor:(name, value)-> 
     return @getStorage name unless value? 
     @setStorage name, value 

angular 
.module 'app.Services' 
.service 'sessionService', SessionService 

SessionService類定義了isAuthenticated屬性(簡單布爾)和user屬性(一個複雜的對象)。這些屬性的值是自動字符串化/解析爲它們被存儲/使用客戶端側由JavaScript提供本地sessionStorage對象檢索。

你加更多的屬性需要。和$rootScope一樣,你要謹慎地添加屬性。不像$rootScope屬性值仍刷新頁面或後退按鈕點擊後可用。

該服務允許用它來註冊的任何數量的作用域。當一個範圍被登記在sessionStorage所有存儲的值被自動分配給該範圍。通過這種方式,所有註冊的範圍始終可以訪問所有會話屬性。

當屬性值被更新,所有註冊的範圍有其相應的值更新。

當角銷燬一個範圍內,可以自動地從註冊範圍的列表中刪除以節省浪費資源。

如果用戶刷新頁面或者點擊後退按鈕,然後角應用被強制重新啓動。通常這意味着你將不得不重建你的當前狀態。該SessionService自動爲您完成此,因爲每個範圍將是從本地存儲恢復它的價值時,他們的應用程序初始化期間註冊。

所以,現在很容易解決範圍之間的兩個數據共享的問題,以及當用戶刷新或點擊後退按鈕恢復值。

下面是一些示例角度代碼,顯示如何使用SessionService類。

在某些控制器註冊與SessionService一個範圍

angular 
.module 'app' 
.controller 'mainCtrl', ($scope, $state, session, security) -> 
    #register the scope with the session service 
    session.register $scope 

    #hook up the 'login' method (see security service) 
    $scope.login = security.login 

    # check the value of a session property 
    # it may well be true if the page has been refreshed 
    if session.isAuthenticated 
     $state.go('home') 
    else 
     $state.go('login') 

在服務

class SecurityService 
    @$inject:['$http','sessionService', 'api'] 
    constructor:(@http, @session, @api) -> 

    login:(username, password) => 
     @http.get "#{@api.base}/security/login/credentials/#{username}/#{password}" 
     .success (user)=> 
      @session.isAuthenticated = true 
      @session.user = user 
     .error (ex)=> 
      # process error 

angular 
.module 'app' 
.service 'securityService', SecurityService 

在UI(玉模板)使用Session值

設置會話值
div(ng-show="isAuthenticated") 
    div Hello {{user.Name}} 
+1

有沒有這個非咖啡標籤版本?這也是唯一可行的解​​決方案嗎?謝謝! – EKet

+1

您可以將coffeescript轉換爲javascript,然後再回到這裏:http://js2coffee.org/。一定會有其他更好的解決方案,起初我認爲必須有一種簡單,有角度的方式來處理諸如後退/刷新按鈕之類的常見事情。但是我找不到它,所以你在這裏看到的是我最好的,最好的,使它的工作。我希望有人發佈更好的解決方案。 – biofractal

+18

+1爲'爲什麼人們發佈咖啡角標解決方案?' – edzillion

0

我面臨同樣的問題,並選擇使用角度曲奇,因爲 只有狀態不是由模板通過ng-init拉動的是登錄用戶 狀態。

我從我們的服務器收到用戶 模型後,在登錄時將用戶ID存儲在cookie中,並在註銷時清除用戶ID cookie。然後在頁面刷新或返回按鈕事件中恢復登錄的用戶狀態 ,我鉤了 $location服務的$locationChangeStart事件。從我的實驗中,這個 事件在位置即將更改但在部分/模板已加載之前觸發。這允許及時加載所需狀態 。

我不相信,我沒有競爭狀態這裏 $scope.loadLoggedInUser(...)採用非同步$ HTTP加載所需的狀態,但到目前爲止 它可靠地爲我工作。

$scope.$on('$locationChangeStart', function() { 
      $log.debug("locationChangeStart"); 
      if (!$scope.appCtx.models.loggedInUser) { 
       var userID = $cookies.get("userID"); 
       if (!userID) { 
        $scope.doLogout(); 
        return; 
       } 
       $scope.loadLoggedInUser(userID, true); 
      } 
     });