someoneHere February 2016

How to keep track of current user in angularJS controllers?

factory / service:

  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();

  }]);
})();

controller:

 (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;
      });

  }]);
})();

I'm keeping track of the current user in the backend, but I want to track my current user in angular across controllers For display purposes, etc..

But, I"m obviously going about this wrong..

Tips, help, much appreciated.

Answers


Zohaib Ijaz February 2016

You can use $cookies to store user data like user name, token etc. You can read docs here https://docs.angularjs.org/api/ngCookies/service/$cookies

Once you get user object from backend service, store it using $cookies and then get that value where needed.

For example, you reload your page, then in app.run phase, get that user object from $cookie and store in some service or $rootScope

I was doing something in a sample app, I don't remember it was 100% OK or not but it will help

(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');
    });
}
})();


Igor February 2016

I believe where you are getting confused is that factory and service are not the same in angular.

  • A factory is created on every injection
  • a service is a singleton and is only created once for the lifetime of the angular app.

The service, in this case, is the best choice to inject into your controllers. The first one to access it will materialize the user data from your server. The rest of the controllers that make use of the service will then use the same service instance so there is no overhead of going to the server for each controller.

Here is the code. The service retrieves the user using a function but persists the result to a local field, this way it is only ever called once. Your controller can then call the function to retrieve it (or even access the field directly if you add some checking logic).

(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}
      }]);
    })();

Controller code

    (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
      


cyan February 2016

I see that we don't talk about Keeping data in browsers memory like localStorage and Cookies. I see, that You want somehow watch state from backend. It is possible, but for performance, better not to do this in all digest cycles. I suggest to set interval - not so little to not overload network and not so big to keep current tracking of information.

Here is answer to question about Angular interval. I think that can help. This solution may be implemented this way:

.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();
  });

I my code i removed dependency injection. I suggest using tool for automatically resolve dependency injection called ng-annotate.

Post Status

Asked in February 2016
Viewed 1,310 times
Voted 8
Answered 3 times

Search




Leave an answer