0

Following is my route configuration

function routes($routeProvider: ng.route.IRouteProvider) {

        let accessResolver = ['UserFactory', (UserFactory: any) => {
            return UserFactory.isAuthenticated();
        }];

        //Configuring routes
        $routeProvider.when('/', {
            templateUrl: '/views/home.html',
            controller: 'HomeController',
            controllerAs: 'homeCtrl',
            resolve: accessResolver
        }).when('/login', {
            templateUrl: '/views/login.html',
            controller: 'LoginController',
            controllerAs: 'loginCtrl'
        }).otherwise({
            redirectTo: '/'
        });
    }

And my route change error handler

function run($rootScope: ng.IRootScopeService, $location: ng.ILocationService) {
        $rootScope.$on("$routeChangeError", () => {
            console.log("Route Change Error");
            $location.url('/login?redirect=' + $location.url());
        });
    }

And the UserFactory

module TheHub {
    export interface IUserFactory {
        isAuthenticated(): ng.IDeferred<String>;
    }

    class UserFactory implements IUserFactory {

        constructor(private $http: ng.IHttpService, private $q: ng.IQService, private $rootScope: any) {
        }

        isAuthenticated(): ng.IDeferred<String> {
            let deferred = this.$q.defer();
            if (this.$rootScope.auth && this.$rootScope.auth.isAuthenticationChecked) {
                if (this.$rootScope.auth.isAuthenticated) {
                    deferred.resolve('OK');
                } else {
                    deferred.reject('Unauthorized');
                }
            } else {
                this.$http.get('secure/user').then(
                    (response: ng.IHttpPromiseCallbackArg<{}>) => {
                        if (!this.$rootScope.auth) {
                            this.$rootScope.auth = {};
                        }
                        this.$rootScope.auth.isAuthenticationChecked = true;
                        this.$rootScope.auth.isAuthenticated = true;
                        deferred.resolve('OK');
                    },
                    (error: any) => {
                        if (!this.$rootScope.auth) {
                            this.$rootScope.auth = {};
                        }
                        this.$rootScope.auth.isAuthenticationChecked = true;
                        deferred.reject('Unauthorized');
                    });
            }
            return deferred;
        }
    }

    function userFactory($http: ng.IHttpService, $q: ng.IQService, $rootScope: any) {
        return new UserFactory($http, $q, $rootScope);
    }

    userFactory.$inject = ['$http', '$q', '$rootScope'];

    angular.module('TheHub').factory('UserFactory', userFactory);
}

The logic here is, I am firing a request to check if the user is already logged in and has a session. The problem is, when the user is not logged in already, the service is failing and the promise is getting rejected. But, I am not sure why, the handler $routeChangeError is not being fired. It is working fine when there is a JavaScript error.

Pavan Andhukuri
  • 1,547
  • 3
  • 23
  • 49
  • 2
    You'd need to use `return deferred.promise`, but you really should completely [avoid the deferred antipattern](http://stackoverflow.com/q/23803743/1048572) – Bergi Mar 20 '16 at 15:31
  • Thanks a lot.. that was a stupid mistake.. Can you post this as an answer so that I can mark it resolved.. – Pavan Andhukuri Mar 20 '16 at 15:42

1 Answers1

1

You've forgotten the .promise so that you only returned the deferred, which was neither awaited nor the resolution value you expected.

But you should avoid the deferred antipattern anyway - just do

isAuthenticated(): ng.IPromise<String> {
    if (this.$rootScope.auth && this.$rootScope.auth.isAuthenticationChecked) {
        if (this.$rootScope.auth.isAuthenticated) {
            return this.$q.resolve('OK');
//          ^^^^^^^^^^^^^^^^^^^^^^
        } else {
            return this.$q.reject('Unauthorized');
//          ^^^^^^^^^^^^^^^^^^^^^^
        }
    } else {
        return this.$http.get('secure/user').then(
//      ^^^^^^
            (response: ng.IHttpPromiseCallbackArg<{}>) => {
                if (!this.$rootScope.auth) {
                    this.$rootScope.auth = {};
                }
                this.$rootScope.auth.isAuthenticationChecked = true;
                this.$rootScope.auth.isAuthenticated = true;
                return 'OK';
//              ^^^^^^
            },
            (error: any) => {
                if (!this.$rootScope.auth) {
                    this.$rootScope.auth = {};
                }
                this.$rootScope.auth.isAuthenticationChecked = true;
                return this.$q.reject('Unauthorized');
//              ^^^^^^^^^^^^^^^^^^^^^
            }
        );
    }
}
Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • 1
    I guess that `ng.IDeferred` should be fixed as well. – Estus Flask Mar 20 '16 at 16:10
  • @estus: Oh, right, I forgot it's typescript. Do you know whether `ng.IPromise` would be the correct type? – Bergi Mar 20 '16 at 16:43
  • 1
    I don't do typings often but yes, I'm positive that it is the correct type for that. Also, `throw` isn't interchangeable with `$q.reject()` in $q. The former will also trigger exception handler, I would save 'throw' for potentially unhandled app errors. – Estus Flask Mar 20 '16 at 17:00