Jak przechowywać bieżący kontekst użytkownika w AngularJS?

92

Mam AuthService, który loguje użytkownika, zwraca obiekt json użytkownika. Chcę ustawić ten obiekt i mieć wszystkie zmiany odzwierciedlone w aplikacji (stan zalogowania / wylogowania) bez konieczności odświeżania strony.

Jak mógłbym to osiągnąć dzięki AngularJS?

Sztuka
źródło

Odpowiedzi:

180

Najłatwiej to osiągnąć, korzystając z usługi. Na przykład:

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

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

Możesz następnie odwołać się do tego w dowolnym ze swoich kontrolerów. Poniższy kod obserwuje zmiany wartości z usługi (przez wywołanie określonej funkcji), a następnie synchronizuje zmienione wartości z zakresem.

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

Następnie możesz oczywiście wykorzystać te informacje w dowolny sposób; np. w dyrektywach, szablonach itp. Możesz to powtórzyć (dostosuj do tego, co musisz zrobić) w swoich kontrolerach menu itp. Wszystko to zostanie automatycznie zaktualizowane po zmianie stanu usługi.

Wszystko bardziej szczegółowe zależy od Twojej implementacji.

Mam nadzieję że to pomoże!

Josh David Miller
źródło
28
@ChrisNicola Właściwie w AngularJS wszystkie usługi są singletonami. Usługa jest więc tworzona przy pierwszym żądaniu (tj. Przez kontroler lub inną usługę), a wszystkie kolejne żądania zwracają dokładnie tę samą instancję.
Josh David Miller,
2
Może tak być, ale jako funkcja możemy usunąć wewnętrzne elementy sposobu, w jaki przechowujemy te informacje z publicznego interfejsu API i do prywatnego interfejsu API. To znacznie ułatwia późniejszą refaktoryzację. Ale funkcja będzie jeszcze powrócić wartość logiczną.
Josh David Miller
7
To może być głupie pytanie ... ale co się stanie, jeśli użytkownik odświeży stronę - czy dane logowania zostały utracone?
Tomba
10
@Tomba To dobre pytanie. :-) Rzeczywiście informacje są tracone przy odświeżaniu. Zwykle będziesz chciał przechowywać pewne informacje o sesji w pliku cookie. Te informacje o sesji można również sprawdzić podczas konfigurowania AuthService. Pomaga to nie tylko w przypadku odświeżania strony, ale także dla osoby otwierającej łącze w nowej karcie.
Josh David Miller
2
@PixMach Masz 100% racji co do krzywej uczenia się. Twoje pytanie będzie zależało w dużej mierze od konkretnego przypadku, ale oto kilka ogólnych wzorców. Zachowaj oddzielenie obaw: interfejs użytkownika związany z inicjowaniem logowania jest oddzielny od samego uwierzytelniania, które jest niezależne od stanu uwierzytelnienia, który jest niezależny od dowolnego menu, które może zależeć od tego stanu. Nawigacja / menu jest często najlepiej obsługiwana przez pojedynczy kontroler, a zagnieżdżone stany (a la ui-router) i rozwiązywanie tras są dobrym sposobem na utrzymanie kontroli uwierzytelniania w stanie SUCHYM. To, o czym napisałeś, brzmi dobrze.
Josh David Miller
5

Poprawiłbym dobrą odpowiedź Josha, dodając, że ponieważ AuthService jest typowo interesujący dla każdego (powiedzmy, kogokolwiek poza widokiem logowania powinien zniknąć, jeśli nikt nie jest zalogowany), może prostszą alternatywą byłoby powiadomienie zainteresowanych stron za pomocą $rootScope.$broadcast('loginStatusChanged', isLoggedIn);(1 ) (2), podczas gdy zainteresowane strony (np. Kontrolerzy) nasłuchują przy użyciu $scope.$on('loginStatusChanged', function (event, isLoggedIn) { $scope.isLoggedIn = isLoggedIn; }.

(1) $rootScopejest wstrzykiwany jako argument usługi

(2) Zauważ, że w prawdopodobnym przypadku asynchronicznej operacji logowania będziesz chciał powiadomić Angular, że transmisja zmieni rzeczy, włączając ją do $rootScope.$apply()funkcji.

Mówiąc o utrzymywaniu kontekstu użytkownika w każdym / wielu kontrolerach, możesz nie być zadowolony z nasłuchiwania zmian logowania we wszystkich z nich i może wolisz słuchać tylko w najwyższym kontrolerze logowania, a następnie dodać inne kontrolery obsługujące logowanie jako dzieci / wbudowane kontrolery tego. W ten sposób kontroler podrzędny będzie mógł zobaczyć odziedziczone właściwości nadrzędne $ scope, takie jak kontekst użytkownika.

Javarome
źródło
4
Głosowanie negatywne za nieprawidłowe wyjaśnienie funkcji fabrycznej. To nieporozumienie zostało już omówione w tym komentarzu na kilka miesięcy przed opublikowaniem odpowiedzi.
Rhys van der Waerden