0

I want to make a more or less generic error handler in my Angular app.

For instance, i get a mail with this link: mysite/messages/151 Clicking this mail: if i am not logged in, my framework returns an 403 (on purpose).

So i created this factory. For now it is only looking for a 403 error and then routing the user to a login page.

app.factory('httpRequestInterceptor', ['$q', '$location', '$rootScope', function($q, $location) {

    return {
        'responseError': function(rejection) {
            if (rejection.status === 403) {

                $location.path('/user/login');
                return $q.reject(rejection);
            }
        }
    };
}]);

In the app.config i added this line:

app.config(['$httpProvider', function($httpProvider)
{

    $httpProvider.interceptors.push('httpRequestInterceptor');

Now, when i get a 403, i go to the right path: /user/login So far, so good.

But... i want to add the $state somehow so i know what the calling url was (messages/151) so i can return to the right place and show the message.

I can not use $state in the factory (error because of some tech stuff i do not understand yet ($http vs $state?), so now i am confused how to get the things done.

So, i want:

1) on 403 error on URL go to login state (works)

2) get login credentials from user (works)

3) goto URL after login is ok (not a clue)

Maybe i should use another approach, but i can not get my head around it. So hopefully someone can help me out?

ProX
  • 297
  • 1
  • 3
  • 16
  • Possibly you cannot inject `$state` directly because of circular dependency. You could try injecting `$injector` and get `$state` from injector and use it. – PSL Aug 12 '14 at 15:26
  • Thanks. I see it is a duplicate question. http://stackoverflow.com/questions/20230691/injecting-state-ui-router-into-http-interceptor-causes-circular-dependency – ProX Aug 14 '14 at 07:59

2 Answers2

1

Ok, this is what i came up with. Thanks!

/**
 * Error handling on httpRequests.
 *
 * generic: use rejection.status like: if (rejection.status === 403) {return     $q.reject(rejection);}
 * custom:  check fromState['current']['name'] for state name
 *
*/
app.factory('httpRequestInterceptor', ['$q', '$location', '$injector', '$timeout', '$stateParams', function($q, $location, $injector, $timeout, $stateParams) {

    return {
        'responseError': function(rejection) {
            var fromState = $injector.get('$state');

            $timeout(function() {
                switch (fromState['current']['name']) {
                    case 'root.messages':
                        $injector.get('$state').go('root.login', $stateParams,
                                {location: false});

                        break;
                }
            }, 2000);
            return $q.reject(rejection);
        }
    };
}]);
ProX
  • 297
  • 1
  • 3
  • 16
0

Broadcast method is good, but we can do this with following way too. If you are using ui-router in order to serve routing requests then you could use this: n your authorization service:

// There is a positive point to use this, your router will not get loaded before authorization
// $stateChangeStart call before routing to other state

rootScope.$on("$stateChangeStart", function (event, toState, toParams, fromState, fromParams) {
    if(!session.exists()){
        // Unauthorize User
        event.preventDefault();
        state.go("error");
    }else{
        // Normal Flow
        location.path(toState.url);
    }
});