Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Circular dependency found: $http <- $templateFactory <- $view <- $state

I have a current 401 check that I'm running with $location which is working fine. However I'd like to swap it over to $state and use ui-router instead. When I do so i get an error code as:

Circular dependency found: $http <- $templateFactory <- $view <- $state <- authHttpResponseInterceptor <- $http <- $compile

My currently code looks fine as I check certain paths and allow no logged in users to view them:

  /* Look for 401 auth errors and then redirect */
  .factory('authHttpResponseInterceptor',['$q','$location', function($q,$location) {

      return {
          response: function(response){
              if (response.status === 401) {
              }

              return response || $q.when(response);
          },
          responseError: function(rejection) {
              var reservedPaths = ['/','/login','/connect','/event'];
              if (rejection.status === 401 && _.contains(reservedPaths,$location.path().trim())) {
                  $location.path('/welcome');

              }
              return $q.reject(rejection);
          }
      };
  }])
  .config(['$httpProvider',function($httpProvider) {
      //Http Intercpetor to check auth failures for xhr requests
      $httpProvider.interceptors.push('authHttpResponseInterceptor');
  }]);

The code I added is as follows.:

  /* Look for 401 auth errors and then redirect */
  .factory('authHttpResponseInterceptor',['$q','$location', **'$state',** function($q,$location, **$state**) {

      return {
          response: function(response){
              if (response.status === 401) {
              }

              return response || $q.when(response);
          },
          responseError: function(rejection) {
              var reservedPaths = ['/','/mycube','/connect','/event'];
              if (rejection.status === 401 && _.contains(reservedPaths,$location.path().trim())) {
                  **$state.go('home');**

              }
              return $q.reject(rejection);
          }
      };
  }])
  .config(['$httpProvider',function($httpProvider) {
      //Http Intercpetor to check auth failures for xhr requests
      $httpProvider.interceptors.push('authHttpResponseInterceptor');
  }]);

Why would adding state cause this issue when it works fine with location?

like image 307
Mr. BigglesWorth Avatar asked Aug 25 '14 23:08

Mr. BigglesWorth


Video Answer


2 Answers

It appears that $state service is resulting in a circular dependency with the $http service. This may be caused by the fact that the templateFactory (see https://github.com/angular-ui/ui-router/blob/master/src/templateFactory.js) is being injected with the $http service in addition to the interceptor itself being composed with the $http service.

To get around this circular dependency issue, you can use the $injector service to wire up the $state service to your interceptor. See the revised code:

/* Look for 401 auth errors and then redirect */
module.factory('authHttpResponseInterceptor', ['$q','$location', '$injector', function($q, $location, $injector) {
    return {
        response: function(response){
            if (response.status === 401) {
            }

            return response || $q.when(response);
        },
        responseError: function(rejection) {
            var reservedPaths = ['/', '/mycube', '/connect', '/event'];
            if (rejection.status === 401 && _.contains(reservedPaths, $location.path().trim())) {
                var stateService = $injector.get('$state');
                stateService.go('home');
            }
            return $q.reject(rejection);
        }
    };
}]);

You can learn more about the $injector service here: https://docs.angularjs.org/api/auto/service/$injector

IMPORTANT

I would recommend using the state change events (see https://github.com/angular-ui/ui-router/wiki#state-change-events) to watch for errors using $stateChangeError and inspecting the error returned from the 401.

like image 189
aaronroberson Avatar answered Oct 12 '22 00:10

aaronroberson


Here is the simplest solution I did and it worked. Inside the factory write:

var $http = $injector.get("$http");

and then use $http as you normally would.

NOTE: If you don't have $injector available in your factory simply inject it as follow

.factory('authHttpResponseInterceptor',['$q','$location','$injector', function($q,$location,$injector) {
}])
like image 40
Hari Das Avatar answered Oct 12 '22 00:10

Hari Das