Как сохранить текущий пользовательский контекст в AngularJS?

92

У меня есть AuthService, который регистрирует пользователя, он возвращает объект json пользователя. Я хочу установить этот объект и отразить все изменения в приложении (состояние входа / выхода) без необходимости обновлять страницу.

Как мне добиться этого с помощью AngularJS?

Изобразительное искусство
источник

Ответы:

180

Самый простой способ добиться этого - использовать службу. Например:

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

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

Затем вы можете ссылаться на это в любом из ваших контроллеров. Следующий код отслеживает изменения значения из службы (путем вызова указанной функции), а затем синхронизирует измененные значения с областью.

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

И затем, конечно, вы можете использовать эту информацию, как считаете нужным; например, в директивах, в шаблонах и т. д. Вы можете повторить это (настроенное в соответствии с тем, что вам нужно сделать) в своих контроллерах меню и т. д. Все это будет обновляться автоматически, когда вы измените состояние службы.

Что-то более конкретное зависит от вашей реализации.

Надеюсь это поможет!

Джош Дэвид Миллер
источник
28
@ChrisNicola На самом деле в AngularJS все сервисы являются одиночными. Таким образом, служба создается в самый первый раз, когда она запрашивается (то есть контроллером или другой службой), и все последующие запросы к ней возвращают тот же самый экземпляр.
Джош Дэвид Миллер
2
Может быть, но в качестве функции мы можем удалить внутреннее устройство того, как мы храним эту информацию, из общедоступного API и в частный API. Это значительно упрощает последующий рефакторинг. Но функция все равно вернет логическое значение.
Джош Дэвид Миллер
7
Это может быть глупый вопрос ... но что произойдет, если пользователь обновит страницу - информация для входа потеряна?
Томба
10
@Tomba Это хороший вопрос. :-) Действительно, при обновлении информация теряется. Обычно вы хотите сохранить некоторую информацию о сеансе в файле cookie. Эту информацию о сеансе также можно проверить при настройке AuthService. Это помогает не только обновлять страницу, но и тем, кто открывает ссылку в новой вкладке.
Джош Дэвид Миллер,
2
@PixMach Вы на 100% правы относительно кривой обучения. Ваш вопрос будет во многом зависеть от конкретного случая, но вот несколько общих закономерностей. Сохраняйте разделение проблем: пользовательский интерфейс, связанный с инициированием входа в систему, отделен от самого auth, который отделен от состояния auth, который отделен от любого меню, которое может зависеть от указанного состояния. Навигация / меню часто лучше всего обрабатываются одним контроллером, а вложенные состояния (а-ля ui-router) и разрешения маршрутов - хороший способ сохранить управление аутентификацией в СУХОМ состоянии. То, что вы написали, звучит правильно.
Джош Дэвид Миллер
5

Я бы изменил хороший ответ Джоша, добавив, что, поскольку AuthService обычно интересует кого угодно (скажем, любой, кроме окна входа в систему, должен исчезнуть, если никто не вошел в систему), возможно, более простой альтернативой было бы уведомить заинтересованные стороны, используя $rootScope.$broadcast('loginStatusChanged', isLoggedIn);(1 ) (2), в то время как заинтересованные стороны (например, контроллеры) будут слушать, используя $scope.$on('loginStatusChanged', function (event, isLoggedIn) { $scope.isLoggedIn = isLoggedIn; }.

(1) $rootScopeвводится как аргумент службы

(2) Обратите внимание, что в вероятном случае асинхронной операции входа в систему вы захотите уведомить Angular о том, что трансляция изменит ситуацию, включив ее в $rootScope.$apply()функцию.

Теперь, говоря о сохранении пользовательского контекста в каждом / многих контроллерах, вы, возможно, не будете довольны прослушиванием изменений входа в систему в каждом из них и, возможно, предпочтете прослушивать только в самом верхнем контроллере входа в систему, а затем добавите другие контроллеры входа в систему в качестве дочерних / встроенные контроллеры этого. Таким образом, дочерний контроллер сможет видеть унаследованные родительские свойства $ scope, такие как ваш пользовательский контекст.

Javarome
источник
4
Проголосовали за неправильное объяснение заводской функции. Это недоразумение уже было рассмотрено в этом комментарии за несколько месяцев до того, как вы опубликовали свой ответ.
Рис ван дер Варден