【问题标题】:How to keep track of current user in angularJS controllers?如何在 angularJS 控制器中跟踪当前用户?
【发布时间】:2016-05-18 13:52:41
【问题描述】:

工厂/服务:

  angular.module('phoenix-template')
  .factory('User', ['$http', function($http){

      function current(){
        $http.get('http://localhost:4000/api/current_user').then(function(res){
          return res.data;
        })
    }

    this.currentUser = current();

  }]);
})();

控制器:

 (function(){
  'use strict';

  angular.module('phoenix-template')
  .controller('NavCtrl', ['$scope','User', function($scope, User){

    $scope.currentUser = User.currentUser;

    $scope.$watch( 'currentUser', function () {
          User.currentUser = $scope.currentUser;
      });

  }]);
})();

我正在后端跟踪当前用户,但我想跨控制器以角度跟踪我的当前用户用于显示等目的。

但是,我显然做错了..

提示,帮助,非常感谢。

【问题讨论】:

  • 您没有向工厂中的current 函数返回任何内容。此外,您不会向工厂构造函数返回任何内容。

标签: angularjs angularjs-service angularjs-controller


【解决方案1】:

我相信您感到困惑的地方是 factoryservice 在角度上不一样。

  • 每次注入都会创建一个工厂
  • 服务是单例的,并且只在 Angular 应用程序的生命周期内创建一次。

在这种情况下,服务是注入控制器的最佳选择。第一个访问它的人将从您的服务器实现用户数据。然后,使用该服务的其余控制器将使用相同的服务实例,因此没有为每个控制器访问服务器的开销。

这里是代码。该服务使用函数检索用户,但将结果保存到本地字段,这样它只会被调用一次。然后,您的控制器可以调用该函数来检索它(如果您添加一些检查逻辑,甚至可以直接访问该字段)。

(function(){
    angular.module('phoenix-template')
      .service('ngUserService', ['$http', function($http){

        var me = this;
        function getUser(callback) {
            // if the user has already been retrieved then do not do it again, just return the retrieved instance
            if(me.currentUser)
                calback(me.currentUser);
            // retrieve the currentUser and set it as a property on the service
            $http.get('http://localhost:4000/api/current_user').then(function(res){
              // set the result to a field on the service
              me.currentUser = res.data;
              // call the callback with the retrieved user
              callback(me.currentUser);
            });
        }
        return {getUser:getUser}
      }]);
    })();

控制器代码

    (function(){
      'use strict';

      angular.module('phoenix-template')
      .controller('NavCtrl', ['$scope','ngUserService', function($scope, ngUserService){
        // call to get the user and set it to your scope variable
        ngUserService.getUser(function(user){$scope.currentUser = user;});

  }]);
})();

【讨论】:

  • 谢谢。我确实对服务/工厂有误解。如果我想清除 current_user,我假设我会在注销后再次调用 ngUserService.getUser(),并在我的 navCtrl 中设置为 $watch()?
  • @someoneHere - 给猫剥皮的方法不止一种,但这里有一种方法。如果 navCtrl 长期存在,您可以允许您的服务进行回调(或如果需要,可以使用它们的数组),通知感兴趣的订阅者用户已更改。向名为 logOut 的服务添加另一个方法,该方法删除用户变量。让 logOut 和 getUser 方法检查是否有注册的回调并执行回调。基本上是一个事件系统。其他控件在启用时将始终获取最新用户,因此它实际上仅适用于长期存在的对象。
  • @someoneHere - 还有一个注意事项。如果可以多次创建/销毁 navCtrl,则在销毁时必须取消注册事件回调。否则,服务最终可能会执行不存在的回调,并可能造成内存泄漏。回调/事件通知也可以使用 $scope.emit 和 $scope.broadcast 来完成,如果频繁创建/销毁侦听器,这可能会更有用。
  • 其实伊戈尔在这里对工厂和服务有一个误解。 Factory 和 Service 都是用于创建服务的 Provider 配方。这意味着工厂和服务都创建服务,AngularJS 中的所有服务都是单例。无论您从 Factory 配方返回什么,都将是 Service 实例,并且将是一个单例。服务配方实际上是用于构建自定义对象,在这里它本质上被用作工厂。 docs.angularjs.org/guide/providers
【解决方案2】:

我看到我们没有谈论将数据保存在浏览器内存中,例如 localStorage 和 Cookie。 我明白了,你想以某种方式从后端观察状态。 这是可能的,但为了性能,最好不要在所有摘要周期中都这样做。 我建议设置间隔——不要太小以不使网络过载,也不要太大以保持当前的信息跟踪。

Here 是关于角间隔问题的答案。我认为这会有所帮助。 这个解决方案可以这样实现:

.controller('NavCtrl', function($scope, User,$interval){
     $scope.loadCurrentUser = function (){
            $scope.currentUser = User.currentUser;
      };

   //Put in interval, first trigger after 10 seconds 
   $interval(function(){
      $scope.loadCurrentUser();
   }, 10000);    

   //invoke initialy
   $scope.loadCurrentUser();
  });

我的代码删除了依赖注入。我建议使用名为ng-annotate 的自动解决依赖注入的工具。

【讨论】:

    【解决方案3】:

    您可以使用 $cookies 来存储用户数据,例如用户名、令牌等。您可以在此处阅读文档https://docs.angularjs.org/api/ngCookies/service/$cookies

    从后端服务获取用户对象后,使用 $cookies 存储它,然后在需要的地方获取该值。

    例如,您重新加载页面,然后在app.run 阶段,从 $cookie 获取该用户对象并存储在某个服务或 $rootScope 中

    我在一个示例应用程序中做某事,我不记得它是否 100% OK,但它会有所帮助

    (function () {
    'use strict';
    
    var app = angular.module('app');
    app.run(runFunction);
    
    runFunction.$inject = ['$rootScope', '$state', '$cookies', '$window'];
    
    /* @ngInject */
    function runFunction($rootScope, $state, $cookies, $window) {
        //// Set User
        var user = $cookie.get('user')
        /* 
         Or you can do something
         if ($window.sessionStorage["user"]) {
            $rootScope.user = JSON.parse($window.sessionStorage["user"]);
         }
        */
        if (user) {
            $rootScope.user = JSON.parse(user);
        } else {
            $rootScope.user = {
                id: 0,
                username: 'Anonymous'
            };
        }
    
        $rootScope.$on('$stateChangeStart', function (event, toState, toParams) {
            var isAuthenticate = toState.authenticate;
            if (isAuthenticate && !$rootScope.user.token) {
                event.preventDefault();
        alert('Please login first');
                $state.go('login');
        });
    }
    })();
    

    【讨论】:

    • 是的。我正在用 localStorage 做类似的事情,存储 jwt。不过,非常感谢您的建议。不过,我主要只是想了解从工厂到控制器的持久数据。
    猜你喜欢
    • 2013-10-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-08
    • 1970-01-01
    • 1970-01-01
    • 2021-07-23
    • 2014-07-10
    相关资源
    最近更新 更多