Comment puis-je gérer le rafraîchissement de la page avec une application D'une Page unique AngularJS?

deux problèmes m'ont troublé comme j'ai appris l'angulaire:

  1. comment restaurer l'état lorsque l'utilisateur rafraîchit la page ou appuie sur le bouton Précédent?

  2. comment partager des données entre des portées appartenant à des contrôleurs différents?

ci-dessous, je montre une solution simple qui fait usage de côté client stockage de la session. Il permet à la fois le partage de données communes et la restauration automatique de l'état après un utilisateur rafraîchit la page ou appuie sur le bouton Précédent.

Note: la solution ci-dessous s'est révélée essentielle pour répondre à la question suivante:

Comment faire pour que le bouton arrière fonctionne avec une machine D'état AngularJS ui-router?

8
demandé sur Community 2014-01-28 17:56:50

3 réponses

la solution dépend de la classe SessionService indiquée ci-dessous. La syntaxe est en coffescript.

SessionService Classe

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

la catégorie SessionService définit la propriété isAuthenticated (simple bool) et la propriété user (un objet complexe) . Les valeurs de ces propriétés sont automatiquement stringifiées / parsed comme ils sont stockés / récupérés en utilisant le côté client local sessionStorage objet fourni par javascript.

vous ajoutez plus de propriétés comme requis . Comme $rootScope vous ajoutez des propriétés avec parcimonie. Contrairement à $rootScope les valeurs des propriétés sont toujours disponibles après un rafraîchissement de page ou un clic de bouton de retour.

le service permet à n'importe quel nombre de portées d'être enregistré avec lui. Lorsqu'un champ est enregistré toutes les valeurs stockées dans sessionStorage sont automatiquement affectés à cette portée. De cette façon, tous les portées enregistrées ont toujours accès à toutes les propriétés de la session.

Lorsqu'une valeur de propriété est mise à jour, toutes les portées enregistrées ont leurs valeurs correspondantes mises à jour.

quand angular détruit un scope, il est automatiquement retiré de la liste des scopes enregistrés pour éviter de gaspiller des ressources.

si un utilisateur rafraîchit la page ou appuie sur le bouton précédent, alors l'application angulaire est forcée de redémarrer. Normalement, ce signifierait que vous auriez à reconstruire votre état actuel. Le SessionService le fait pour vous automatiquement car chaque scope aura ses valeurs restaurées à partir du stockage local quand elles sont enregistrées lors de l'initialisation de l'application.

donc maintenant il est facile de résoudre le problème du partage des données entre les portées ainsi que la restauration des valeurs lorsque l'utilisateur rafraîchit ou appuie sur le bouton Précédent.

voici un exemple de code angulaire qui montre comment utiliser la classe SessionService .

enregistrer une portée avec SessionService dans quelque contrôleur

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

Définir les valeurs de Session dans un 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

utiliser les valeurs de Session dans L'UI (Jade template)

div(ng-show="isAuthenticated")
    div Hello {{user.Name}}
5
répondu biofractal 2014-11-21 11:23:19

j'ai été confronté à la même question et a choisi d'utiliser des cookies angulaires, depuis le le seul état qui n'est pas tiré par le modèle via ng-init est l'utilisateur connecté état.

je stocke le nom d'utilisateur dans un cookie lors de la connexion après avoir reçu l'utilisateur modèle de notre serveur et j'efface le cookie d'ID utilisateur sur la déconnexion. Ensuite, pour récupérer l'état utilisateur connecté sur un événement de rafraîchissement de page ou de retour de bouton, j'accroche le $location service $locationChangeStart événement. De mon l'expérimentation, ce l'événement est déclenché au point de l'emplacement est sur le point de changer, mais avant le partielle/modèle a été chargé. Cela permet à l'état nécessaire d'être chargé juste dans le temps.

Je ne suis pas convaincu que je n'ai pas une condition de race ici comme $scope.loadLoggedInUser(...) utilise asynch $ http pour charger l'état nécessaire mais jusqu'à présent il a travaillé de manière fiable pour moi.

$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);
            }
        });
0
répondu Kenosis 2015-07-28 00:16:34

il y a une solution simple lorsque vous utilisez le noeud .js pour configurer votre serveur. Vous devez organiser votre routage côté client d'une manière qui fait de vos liens de route des expressions régulières uniques. En application.js vous aurez:

(function () {
var app = angular.module('dataCollector', ['ngRoute']);

app.config(['$routeProvider', '$locationProvider',

    function ($routeProvider, $locationProvider) {

    $routeProvider
        .when('/', {
            templateUrl: 'home.html',
            controller: 'mainController'
        })

        .when('/about', {
            templateUrl: 'about.html',
            controller: 'aboutController'
            })

        .when('/login', {
            templateUrl: 'login.html',
            controller: 'loginController'
        });

    $locationProvider.html5Mode(true);
}]);

app.controller('mainController', ['$scope', function ($scope) {
}]);

})();

dans cet exemple, toutes les routes , sauf '/' , peuvent être écrites dans un schéma d'expression régulière [A-Za-z] . Ainsi, le serveur.fichier js serait comme ceci:

 var express = require('express');
 var http = require('http');
 var fs = require('fs');
 var path = require('path');

 var app = express();
 app.use(express.static('public'));

 app.get(/[A-Za-z]/, function (req, res) {
     res.sendFile(path.join(__dirname + '/index.html'));
 });


 http.createServer(app).listen(80);

maintenant chaque GET demande qui correspond au regex [A-Za-z] fera une réponse avec index.html (qui sont nos routes appelées lors du rafraîchissement d'une page par exemple /about ). Toute autre demande GET répondra avec un fichier du répertoire /public (ici chaque fichier avec l'extension *.html ). Cela permet de rafraîchir le spa AngularJS de manière appropriée.

0
répondu D Wal 2018-04-07 13:38:38