Sign up ×
Stack Overflow is a community of 4.7 million programmers, just like you, helping each other. Join them; it only takes a minute:

I am using the $http interceptor to show a login modal when $auth fails. Here is a brief set-up I have:

$provide.factory('modalWhenLoggedOut', ['$q', '$injector', '$rootScope',
          function($q, $injector, $rootScope) {

        return {

             responseError: function(rejection) {

                 // $injector.get to fix circular dependency error
                 var loginModal = $injector.get('LoginModalService');
                 var $http = $injector.get('$http');
                 var $state = $injector.get('$state');

                 // Check for reasons instead of status code
                 var rejectionReasons = ['token_not_provided', 'token_expired', 'token_absent', 'token_invalid'];

                 // Loop through each rejection reason and redirect
                 angular.forEach(rejectionReasons, function(value, key) {

                     if(rejection.data.error === value) {
                        // Show the login modal
                         var deferred = $q.defer();

                         loginModal()
                           .then(function () {
                             deferred.resolve( $http(rejection.config) );
                         })
                         .catch(function () {
                             $state.go('index');
                             deferred.reject(rejection);
                        });

                        return deferred.promise;
                     }
                 });

                 return $q.reject(rejection);
             }
         }
}]);

// Push the new factory onto the $http interceptor array
$httpProvider.interceptors.push('modalWhenLoggedOut');

The above code works fine. But the problem I have is when the api throws multiple auth failure error, the interceptor opens up multiple modals at the same time. Usually in 1 page I might have 2-3 times various services contacting the backend api and when the auth fails, all of those api returns auth failure error during invalid tokens. This interceptor is picking it up as 3 taken_invalid errors and showing 3 login modals 1 on top of each other. How do I prevent this?

How can I make sure the interceptor only shows 1 login modal no matter how many times the auth failure occurred?

My Service Looks something like this:

.service('LoginModalService', ['$modal', '$rootScope', 
            function($modal, $rootScope) {

                    function updateRootScope() {
                            $rootScope.loginProgress = false;
                    }

                  if ($rootScope.loginProgress = false) {
                    return function() {
                      var instance = $modal.open({
                        templateUrl: rootPath + 'views/partials/LoginModalTemplate.html',
                        controller: 'LoginModalCtrl'
                      })

                    return instance.result.then(updateRootScope);
                  };
                  }
}])

In the service I am trying to use $rootScope.loginProgress as a switch to figure out if a login modal is opened or not. However, I am not sure how to return an empty promise if modal is already opened (when $rootScope.loginProgress is true).

share|improve this question
1  
Have you tried wrapping your "responseError" function in a service that has a flag to check wether the modal has been displayed already or not? – XelharK Jul 24 at 15:12
    
not yet. I am right now trying to store modalopen in localstorage and check that in foreach loop. Not sure if that method will work. I will update back if I had any luck on that., – Neel Jul 24 at 15:27
    
@XelharK I am thinking storing in $rootScope is better than storing in localStorage. Taking your suggestion, I thought I can perhaps use the $rootScope as a switch by setting $rootScope.loginProgress as true when modal opens and the consecutive modals check this before deciding the open the modal or not. However, I am not sure how to return an empty promise to interceptor when $rootScope.loginProgress is true. I have updated my question with my service attempt. Can you help me on how I can proceed here please? – Neel Jul 24 at 18:42
    
thanks heaps for your comment yesterday @XelharK That helped me in finally resolving my issue. I decided to use the http-auth-interceptor and then changing the $rootScope.loginProgress when the login modal is opened. This seems to work. I have added that as the answer. Do let me know if there is a better way to do it. Thank you so much for your help. Without your comment, I would not have gone forward on this. :) Cheers! – Neel Jul 26 at 17:44
1  
Yeah that's pretty much what I said. Sorry for not answering, I was away during the weekend. Anyway, I think you can wrap this all up in a service and use a simple configuration line in your conf file to do the binding, so you have the most modularity :) – XelharK Jul 27 at 8:49

1 Answer 1

up vote 0 down vote accepted

To overcome my issue, I am now using http-auth-interceptor interceptor and then changing the $rootScope.loginProgress based on the login modal open status. The consecutive modals that are opened due to multiple 401s will check for this login modal status and then decides to open a modal or not. Using http-auth-interceptor, I am able to add the switch by watching the 'event:auth-loginRequired'. Here is the code I am using:

scope.$on('event:auth-loginRequired', function() {      
            if(!$rootScope.loginProgress) {
                        $rootScope.loginProgress = true;
                        LoginModalService()
                            .then(function () {
                              authService.loginConfirmed();
                                    $rootScope.loginProgress = false;
                          })
                          .catch(function () {
                              authService.loginCancelled();
                                    $rootScope.loginProgress = false;
                          });
            }
});

Where LoginModalService() is the service that opens the login modal.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.