Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
228 views
in Technique[技术] by (71.8m points)

coffeescript - How do I handle page refreshing with an AngularJS Single Page Application

Two problems have troubled me as I have learned angular:

  1. How do I restore state when the user refreshes the page or hits the back button?

  2. How do I share data between scopes belonging to different controllers?

Below I show a simple solution that makes use of client-side session storage. It allows for both the sharing of common data and the automatic restoration of state after a user refreshes the page or hits the back button.

Note: The solution below proved essential to answer the following question:

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

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The solution depends on the SessionService class shown below. The syntax is coffeescript.

SessionService Class

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

The SessionService class defines the isAuthenticated property (simple bool) and the user property (a complex object) . The values of these properties are automatically stringified / parsed as they are stored / retrieved using the client-side local sessionStorage object supplied by javascript.

You add more properties as required. Like $rootScope you add properties sparingly. Unlike $rootScope the property values are still available after a page refresh or back button click.

The service allows any number of scopes to be registered with it. When a scope is registered all the stored values in sessionStorage are automatically assigned to that scope. In this way all the registered scopes always have access to all the session properties.

When a property value is updated, all the registered scopes have their corresponding values updated.

When angular destroys a scope it is automatically removed from the list of registered scopes to save wasting resources.

If a user refreshes the page or hits the back button then the angular application is forced to restart. Normally this would mean you would have to reconstruct your current state. The SessionService does this for you automatically as each scope will have its values restored from local storage when they are registered during the app initialisation.

So now it is easy to solve the problem of both sharing data between scopes as well as restoring values when the user refreshes or hits the back button.

Here is some sample angular code that shows how to use the SessionService class.

Register a scope with SessionService in some Controller

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

Set Session values in a service

 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

Use Session values in UI (Jade template)

div(ng-show="isAuthenticated")
    div Hello {{user.Name}}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...