سؤال

I'm starting to use the MEAN Stack taking advantage of the angular-fullstack generator. It comes with an Authentication service which has a method that returns the current user object.

I'm successfully retrieving the Authenticated User object from my Controller this way:

angular.module('myApp')
   .controller('CompanyOwnerCtrl', function ($scope, $http, Auth) {
       $scope.user = Auth.currentUser();

});

$scope.user actually holds the user object since I'm able to display all its attributes in my view:

{{user}} //prints successfully all user data

My problem is that I'm unable to use the _id attribute in my controller to make a call to the backend and retrieve data from another collection

angular.module('myApp')
   .controller('CompanyOwnerCtrl', function ($scope, $http, Auth) {
       var u = Auth.currentUser();
       $scope.user = u;

       //retrieve additional data
       $http.get('/api/companies/' + $scope.user._id) 
         .then(function(result) {
            $scope.company = result.data; 
       }); 

});

If I try the code above to retrieve the company information it says the $scope.user._id is undefined BUT if I write in my view

{{user._id}}

It displays the user ID properly. I may not be using the best approach since this project is just to learn the stack, but, does anyone know why I can't use the user id the way I'm doing it in my controller?

Edit: Here's the Authentication Service

'use strict';

angular.module('myApp')
.factory('Auth', function Auth($location, $rootScope, Session, User, $cookieStore) {

// Get currentUser from cookie
$rootScope.currentUser = $cookieStore.get('user') || null;
$cookieStore.remove('user');

return {

  /**
   * Authenticate user
   * 
   * @param  {Object}   user     - login info
   * @param  {Function} callback - optional
   * @return {Promise}            
   */
  login: function(user, callback) {
    var cb = callback || angular.noop;

    return Session.save({
      email: user.email,
      password: user.password
    }, function(user) {
      $rootScope.currentUser = user;
      return cb();
    }, function(err) {
      return cb(err);
    }).$promise;
  },

  /**
   * Unauthenticate user
   * 
   * @param  {Function} callback - optional
   * @return {Promise}           
   */
  logout: function(callback) {
    var cb = callback || angular.noop;

    return Session.delete(function() {
        $rootScope.currentUser = null;
        return cb();
      },
      function(err) {
        return cb(err);
      }).$promise;
  },

  /**
   * Create a new user
   * 
   * @param  {Object}   user     - user info
   * @param  {Function} callback - optional
   * @return {Promise}            
   */
  createUser: function(user, callback) {
    var cb = callback || angular.noop;

    return User.save(user,
      function(user) {
        $rootScope.currentUser = user;
        return cb(user);
      },
      function(err) {
        return cb(err);
      }).$promise;
  },

  /**
   * Change password
   * 
   * @param  {String}   oldPassword 
   * @param  {String}   newPassword 
   * @param  {Function} callback    - optional
   * @return {Promise}              
   */
  changePassword: function(oldPassword, newPassword, callback) {
    var cb = callback || angular.noop;

    return User.update({
      oldPassword: oldPassword,
      newPassword: newPassword
    }, function(user) {
      return cb(user);
    }, function(err) {
      return cb(err);
    }).$promise;
  },

  /**
   * Gets all available info on authenticated user
   * 
   * @return {Object} user
   */
  currentUser: function() {
    return User.get();
  },


  /**
   * Simple check to see if a user is logged in
   * 
   * @return {Boolean}
   */
  isLoggedIn: function() {
    var user = $rootScope.currentUser;
    return !!user;
  },
};

});

هل كانت مفيدة؟

المحلول

Here's one possible and working solution for this problem. Keep in mind that this particular solution works for the angular-fullstack generator and I have no idea if there is a similar implementation in the backend for other generators

Instead of using the Auth.currentUser() method I ended up calling the /api/users/me end point which is connected to the current user session and therefore returns all the current user information.

$http.get('/api/users/me') 
  .then(function(result) {
    $scope.userId = result.data._id;
    // Do whatever you need to do with the userId here.

});

It is better to call the /api/users/me in every page instead of storing the userId in a session for security reasons. Remember to add the authenticate: true in your route to make sure there will always be a logged in user.

نصائح أخرى

My guess would be that by the time the line of code making the $http call is reached the user object on the $scope is not populated, but after a little while it is and hence why you can check for the _id in your view, maybe due to some async operation? How about watching the user object and only making the call once it exists?

$scope.$watch(Auth.currentUser,function(user){
       if(user){
          $scope.user=user;
          $scope.GetCompanyDetails(user._id);
       }
},true);

$scope.GetCompanyDetails=function(userId){
       $http.get('/api/companies/' + userId) 
         .then(function(result) {
            $scope.company = result.data; 
       }); 
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top