Comment stocker un contexte utilisateur actuel dans AngularJS?

92

J'ai un AuthService, qui connecte un utilisateur, il renvoie un objet json utilisateur. Ce que je veux faire, c'est définir cet objet et faire refléter toutes les modifications dans l'application (état connecté / déconnecté) sans avoir à actualiser la page.

Comment pourrais-je accomplir cela avec AngularJS?

Art
la source

Réponses:

180

Le moyen le plus simple d'y parvenir est d'utiliser un service. Par exemple:

app.factory( 'AuthService', function() {
  var currentUser;

  return {
    login: function() { ... },
    logout: function() { ... },
    isLoggedIn: function() { ... },
    currentUser: function() { return currentUser; }
    ...
  };
});

Vous pouvez ensuite le référencer dans n'importe lequel de vos contrôleurs. Le code suivant surveille les modifications d'une valeur du service (en appelant la fonction spécifiée), puis synchronise les valeurs modifiées avec l'étendue.

app.controller( 'MainCtrl', function( $scope, AuthService ) {
  $scope.$watch( AuthService.isLoggedIn, function ( isLoggedIn ) {
    $scope.isLoggedIn = isLoggedIn;
    $scope.currentUser = AuthService.currentUser();
  });
});

Et puis, bien sûr, vous pouvez utiliser ces informations comme bon vous semble; par exemple dans les directives, dans les modèles, etc. Vous pouvez répéter ceci (personnalisé selon ce que vous devez faire) dans vos contrôleurs de menu, etc. Tout sera mis à jour automatiquement lorsque vous changez l'état du service.

Tout ce qui est plus spécifique dépend de votre implémentation.

J'espère que cela t'aides!

Josh David Miller
la source
28
@ChrisNicola En fait, dans AngularJS, tous les services sont des singletons. Ainsi, le service est créé la toute première fois qu'il est demandé (c'est-à-dire par un contrôleur ou un autre service) et toutes les demandes suivantes renvoient exactement la même instance.
Josh David Miller
2
Cela pourrait être, mais en tant que fonction, nous pouvons supprimer les éléments internes de la façon dont nous stockons ces informations de l'API publique et dans l'API privée. Cela rend la refactorisation ultérieure beaucoup plus facile. Mais la fonction serait toujours revenir un booléen.
Josh David Miller
7
Cela peut être une question stupide ... mais que se passe-t-il si l'utilisateur actualise la page - les informations de connexion sont-elles perdues?
Tomba
10
@Tomba C'est une bonne question. :-) En effet les informations sont perdues lors du rafraîchissement. Habituellement, vous souhaiterez stocker certaines informations de session dans un cookie. Ces informations de session peuvent également être vérifiées lors de la configuration du AuthService. Cela aide non seulement pour les actualisations de page, mais aussi pour quelqu'un qui ouvre un lien dans un nouvel onglet.
Josh David Miller
2
@PixMach Vous avez raison à 100% sur la courbe d'apprentissage. Votre question dépendra en grande partie du cas particulier, mais voici quelques tendances générales. Gardez la séparation des préoccupations: l'interface utilisateur liée au lancement d'une connexion est distincte de l'authentification elle-même, qui est distincte de l'état de l'authentification, qui est distinct de tout menu pouvant dépendre dudit état. Nav / menu est souvent mieux géré par un seul contrôleur, et les états imbriqués (a la ui-router) et les routes résolues sont un bon moyen de garder les contrôles d'authentification DRY. Ce que vous avez écrit semble juste.
Josh David Miller
5

Je modifierais la bonne réponse de Josh en ajoutant que, comme un AuthService est généralement d'intérêt pour n'importe qui (disons, n'importe qui mais la vue de connexion devrait disparaître si personne n'est connecté), peut-être qu'une alternative plus simple serait d'informer les parties intéressées en utilisant $rootScope.$broadcast('loginStatusChanged', isLoggedIn);(1 ) (2), tandis que les parties intéressées (comme les contrôleurs) écouteraient en utilisant $scope.$on('loginStatusChanged', function (event, isLoggedIn) { $scope.isLoggedIn = isLoggedIn; }.

(1) $rootScopeétant injecté comme argument du service

(2) Notez que, dans le cas probable d'une opération de connexion asynchrone, vous voudrez informer Angular que la diffusion changera les choses, en l'incluant dans une $rootScope.$apply()fonction.

Maintenant, en parlant de garder le contexte utilisateur dans tous / de nombreux contrôleurs, vous pourriez ne pas être heureux d'écouter les changements de connexion dans chacun d'entre eux, et préférer peut-être écouter uniquement dans un contrôleur de connexion le plus élevé, puis ajouter d'autres contrôleurs prenant en charge la connexion en tant qu'enfants / contrôleurs embarqués de celui-ci. De cette façon, le contrôleur enfants pourra voir les propriétés héritées du parent $ scope telles que votre contexte utilisateur.

Javarome
la source
4
Évalué pour une explication incorrecte de la fonction d'usine. Ce malentendu a déjà été résolu dans ce commentaire des mois avant que vous ne publiiez votre réponse.
Rhys van der Waerden