0

Okay, so I'm pretty sure I've found the answer multiple times - I just don't understand it.

I'm building a single page application which on each $routeChangeStart checks if the user is logged in. If the user isn't log in, redirect to login page. My issue is that configService.isLoggedIn() is using $http, meaning it's asynchronous and the rest of the code won't wait for it to be resolved.

So the question in short: I need the isLoggedIn() function to be resolved before continuing with any other code.

I've seen a lot on $q.defer() but I can't wrap my head around it.

Thanks in advance.

app.service('configService', ['$http', '$q', '$location', '$rootScope', function ($http, $q, $location, $rootScope) {
    var self = this;

    this.isLoggedIn = function () {
        $http.get('/internalAPI.php?fn=login').then(function (result) {
            if (result.data.isLoggedIn === true) {
                $rootScope.isLoggedIn = true;
            }
            else {
                $rootScope.isLoggedIn = false;
            }
        }, function() {
            $rootScope.isLoggedIn = false;
        });
        return $rootScope.isLoggedIn;
    }
}]);

app.service('navigationService', ['$rootScope', '$location', '$timeout', 'configService', function ($rootScope, $location, $timeout, configService) {

    var self = this;

    $rootScope.$on('$routeChangeStart', function (event, next, current) {
        if (configService.isLoggedIn() !== true) {
            // no logged in user, redirect to /login
            if (next.templateUrl != "resources/views/login.php") {
                $location.path("/login");
                $rootScope.subTitle = 'Login';
            }
        //user is logged in but is trying to view the login page, redirect
        } else if (next.templateUrl == 'resources/views/login.php') {
            $location.path('/');
        }
2
  • 1
    Why so complicated? What we do and what I think is standard is: Let the server return status code 401 when user is not loged anymore. Then we have an interceptor on client side (also in angularjs) which redirects the user to login view if this status code is returned by a request. Commented Feb 15, 2016 at 13:07
  • Agree with Rene. This is more elegant way of handling the authentication than explicitly sending separate http request. Commented Feb 15, 2016 at 13:16

2 Answers 2

1

You can just return promise from your function and operate on this promise object. According to Angular $http documentation the $http object is based on promise mechanism

app.service('configService', ['$http', function ($http) {
    var self = this;

    this.isLoggedIn = function () {
        return $http.get('/internalAPI.php?fn=login');
    }
}]);

app.service('navigationService', ['$rootScope', '$location', '$timeout', 'configService', function ($rootScope, $location, $timeout, configService) {

    var self = this;

    $rootScope.$on('$routeChangeStart', function (event, next, current) {
        configService.isLoggedIn().then(function(result) {
            if (result !== true) {
                // no logged in user, redirect to /login
                if (next.templateUrl != "resources/views/login.php") {
                    $location.path("/login");
                    $rootScope.subTitle = 'Login';
                }
            //user is logged in but is trying to view the login page, redirect
            } else if (next.templateUrl == 'resources/views/login.php') {
                $location.path('/');
            }
        }
    }
}
Sign up to request clarification or add additional context in comments.

2 Comments

Please don't insert scopes into services. thats just plain bad practice.
Yes, you're right. I just modify code from question to answer this question
0

Many thanks for that. Went for the approach Rene M. mentioned regarding building an interceptor and let the server-side scripts handle the authentication.

Definitely does the trick, if the 403 status is returned then redirect the user to the login page and update the isLoggedIn variable. Refactoring the code to remove use of the rootScope, was a dirty workaround until I got a hang of the whole angular way of authentication.

Attached a simple example below in case anyone would stumble upon this in the future.

app.config(['$routeProvider', '$locationProvider', '$httpProvider', function ($routeProvider, $locationProvider, $httpProvider) {
    $httpProvider.interceptors.push('responseObserver');

app.factory('responseObserver', ['$location', '$q', function ($location, $q) {
    return {
        'responseError': function (errorResponse) {
            switch (errorResponse.status) {
            case 403:
                //Place logic here
                break;
            case 500:
                //Place logic here
                break;
            }
            return $q.reject(errorResponse);
        }
    };
}]);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.