0

I'm struggling with AngularJS and access to connected user info here. My goal is to save the info of the connected user in a Service, so that is available throughout the app. So this is how I do it:

The login function is exposed through a Login service, and its code is the following:

(function(){
var $loginService = angular.module("RockMyTask.LoginService", [
    "satellizer",
    "RockMyTask.ApiService"
]);

/**
 * Login service
 *
 * function login(identifier, password, after)
 *  Logs the given user. Global data about the user are registered in the root scope.
 *  @param identifier The user's identifier (either email or password)
 *  @param password The user's password
 *  @param success (optional) A callback to execute when the user is successfully logged in. This callback is passed
 *  the response object.
 *  @param failure (optional) A callback to execute when the log in fails. This callback is passed the response
 *  object.
 *
 * function restore()
 *  If the user was already logged in, restore the user data in the rootScope.
 *
 * function connectedUser()
 *  Return the data of the currently connected user. If the user is not connected an empty object is returned.
 *  If the user data hasn't be fetched yet, then an empty object is returned and this object will be filled with
 *  the user data as soon as it is received.
 */
$loginService.factory("Login", ["$auth", "$rootScope", "User",
    function($auth, $rootScope, User) {
    var obj = {};
    var connectedUser = {};

    obj.logout = function() {
        $auth.logout();
        //Authorization.clear();
        connectedUser = null;
    };

    obj.login = function(identifier, password, success, failure) {
        var credentials = {
            user_identifier: identifier,
            password: password
        };

        $auth.login(credentials).then(function(auth_response) {
            // fetch user data (with both spectator and rockstar flags set to true)
            User.me(true, true).then(function(response) {
                connectedUser = response.data;
                //TODO add check for DEBUG_MODE
                console.log("Received connected user data and stored it in connectedUser var");
            }, function() {
                connectedUser = {};
            });

            // execute provided success callback
            if (_.isFunction(success)) {
                success(auth_response);
            }
        }, function(response) {
            connectedUser = null;

            // execute provided failure callback
            if (_.isFunction(failure)) {
                failure(response);
            }
        });
    };

    obj.restore = function() {
        if ($auth.isAuthenticated()) {
            User.me(true, true).then(function(response) {
                connectedUser = response.data;
            }, function() {
                connectedUser = null;
            });
        } else {
            connectedUser = null;
        }
    };

    obj.getConnectedUser = function(){
        if($auth.isAuthenticated && !connectedUser){
            User.me(true, true).then(function(response) {
                connectedUser = response.data;
            }, function() {
                connectedUser = null;
            });
        }
        return connectedUser;
    };

    obj.updateUserInfo = function(user){
        connectedUser = user;
    };

    obj.isConnectedUserRockstar = function(){
        return connectedUser.rocker != null;
    };
    obj.isConnectedUserSpectator = function(){
        return connectedUser.spectator != null;
    };

    return obj;
}]);
})();

As you may observe in the code, upon successful login, I launch an HTTP request (User.me(true, ture)) which then stores the returned data (representing info about connected user) in an ad hoc variable of the service, connectedUser.

To access the connected user info from any point of the application, I've implemented a function in the Login service called getConnectedUser, whose code is reported here:

obj.getConnectedUser = function(){
        if($auth.isAuthenticated && !connectedUser){
            User.me(true, true).then(function(response) {
                connectedUser = response.data;
            }, function() {
                connectedUser = null;
            });
        }
        return connectedUser;
    };

This function checks if the user is indeed authenticated and if the variable connectedUser has been already correctly populated and if not it triggers again the HTTP function to retrieve the data (otherwise it simply returns the connectedUser var).

Now, my problem is the following. The page I redirect the user to, after successful login, uses a controller, to which I've passed the Login service. The controller tries to retrieve the connected user info but the result is a null pointer. What am I doing wrong??

The code in the controller (just in case even if very simple):

$scope.user = Login.getConnectedUser();

EDIT 1 Looking at the console in the browser I see that the HTTP request has success and the returned data is:

{"id":3,"email":"iCartwright@hotmail.com","name":"Michele","surname":"Imperiali","locale":"it_IT","picture":"https:\/\/storage.rockmytask.it\/users\/profile_image\/3.jpeg","birthday":"1982-06-23","gender":"M","country":"IT","province":"Lombardia","city":"Milano","zip":"20100","street":"190 Grover Expressway","mobile_phone":"(437)924-8282","home_phone":"239-250-3166x783","username":"spectator","validated":true,"timezone":"Europe\/Rome","created_at":"2016-04-01T12:50:53+0000","rocker":null,"spectator":{"description":"I need help with my garden !"}}

As previously stated, when I try to access on the variables of $scope.user in the controller I get a null pointer exception.

halfer
  • 19,824
  • 17
  • 99
  • 186
miks87
  • 193
  • 1
  • 5
  • 16
  • Can you confirm that you have the correct data in `User.me(true, ture)` by consol.logging it? – Jahongir Rahmonov Aug 25 '16 at 18:04
  • @JahongirRahmonov yes I can. I've added more details in the question – miks87 Aug 25 '16 at 18:12
  • Can you post full login service code? – Jahongir Rahmonov Aug 25 '16 at 18:19
  • Done! Hope it helps – miks87 Aug 25 '16 at 18:35
  • 1
    Read http://stackoverflow.com/questions/39151752/typescript-javascript-objects, or http://stackoverflow.com/questions/39133214/storing-json-data-from-a-file-in-local-variable#comment65619682_39133214, or any of the many questions asking the same thing. – JB Nizet Aug 25 '16 at 18:38
  • Thanks @JBNizet I was indeed worring that I was doing something wrong because of the asynchronous HTTP requests. Your hint helped me figuring out the problem! (I'm going to post the solution shortly) – miks87 Aug 25 '16 at 20:02

1 Answers1

-1

I think the issue has to do with the

, function() {
            connectedUser = null;
        }

Is there a reason you are setting connectedUser to null? If the reason is because you want to set it to null if you get an error from the backend or a bad return then doing :

obj.getConnectedUser = function(){
    if($auth.isAuthenticated && !connectedUser){
        User.me(true, true).then(function(response) {
            connectedUser = response.data;
        }, function(error) {
            connectedUser = null;
        });
    }
    return connectedUser;
};

This then would only set connectUser to null if you get a bad response, As of right now it looks like the connectedUser is always getting set to null and explaining your null pointer.

Jeffrey Jarry
  • 166
  • 2
  • 6
  • Thanks Jeffrey but I don't think your solution is good. The notation for the `then` function is to define the two functions for on success and on failure. My function as is, being the second parameter, is only triggered in case of failure of the HTTP request. In fact, even if I comment the `connectedUser = null` body, the problem is still the same... – miks87 Aug 25 '16 at 18:49
  • 1
    Sorry, I didnt have enough reputation yet to comment. My other thought would be the function should actually return the promise instead of waiting for the promise within the function. So you would have the function return the http request. then in the controller be Login.getConnectedUser().then(function(response){ $scope.user = response.data}); – Jeffrey Jarry Aug 25 '16 at 19:02
  • Hey Jeffrey, yes you are right. I'm not doing as you said because I want to perform the then in the service, to store there the connectedUser info and make it available to subsequent requests from other parts of the application. However your comment pointed me in the right direction. I'm going to post my solution shortly. Cheers! – miks87 Aug 25 '16 at 20:04