Question

Here's my code in the service.

this.loginUser = function(checkUser) {
    Parse.User.logIn(checkUser.username, checkUser.password, {
        success: function(user) {
            $rootScope.$apply(function (){
                $rootScope.currentUser = user;
            });
        }
    });
};

Here's my code in the controller:

$scope.logIn = function(){
    authenticationService.loginUser($scope.checkUser);
        console.log($scope.currentUser)
};

So, what I want to do is, execute some code AFTER the completion of AJAX call, whose success function sets the value of $scope.currentUser, which, I can use for some conditional logic (like redirecting etc) The success function is correctly setting the value, but the console.log should be executed AFTER the execution of authenticationService.loginUser() function.

Was it helpful?

Solution

You need to return a promise using $q and act on that.

For instance in your service:

this.loginUser = function(checkUser) {
    var deferred = $q.defer();
    Parse.User.logIn(checkUser.username, checkUser.password, {
        success: function(user) {
            $rootScope.$apply(function (){
                $rootScope.currentUser = user;
            });
            deferred.resolve();
        }
    });
    return deferred.promise;
};

Then in your controller act on the success:

$scope.logIn = function(){
    authenticationService.loginUser($scope.checkUser).then(function() {
        console.log($rootScope.currentUser));
    });
};

OTHER TIPS

Try using $rootScope.$broadcast in your service then listen for it in your controller:

Service

Parse.User.logIn(checkUser.username, checkUser.password, {
    success: function(user) {
        $rootScope.$apply(function (){
            $rootScope.currentUser = user;
            $rootScope.$broadcast('user.online');
        });
    }
});

Controller

$scope.$on('user.online',function(){
    [ DO STUFF HERE ]
});

This isn't the best way to do this though @comradburk's use of $q is probably a better way.

If your application wait for external result, you should use $q for return a promise. If you are using angular-route or ui-router components, you can use resolve param for this. Take a look ngRoute documentation. In there has a example based in resolve param.

https://docs.angularjs.org/api/ngRoute/service/$route

i think you have two options here

  1. as answered by comradburk, use promises:

in Services:

this.loginUser = function(checkUser) {
var deferred = $q.defer();
Parse.User.logIn(checkUser.username, checkUser.password, {
    success: function(user) {
        deferred.resolve(user);
    }
});
return deferred.promise;

};

in controller:

$scope.logIn = function(){
authenticationService.loginUser($scope.checkUser).then(function(user) {
    $scope.currentUser = user;
});
};
  1. using resolve, resolve your service at route level (...or state level in case you are using ui-router) before controller initialization and insert it as a dependency - helpful in scenarios like user authentication where you dont want user to be able to navigate further if authentication fails. from docs https://docs.angularjs.org/api/ngRoute/service/$route

YOMS (Yet One More Solution):

    this.loginUser = function(checkUser, onSuccess) {
        Parse.User.logIn(checkUser.username, checkUser.password, {
            success: function(user) {
                $rootScope.$apply(function() {
                    $rootScope.currentUser = user;
                    if (typeof onSuccess == 'function') onSuccess(user); // optionally pass data back
                });
            }
        });
    };

    $scope.logIn = function(user, function(returnedUser) {
    // console.log(returnedUser); // Optional, The returned user
        console.log($scope.currentUser)
    }) {
        authenticationService.loginUser($scope.checkUser);
    };
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top