0
votes

I have just added a http response interceptor to one of my modules, and have encountered a circular dependency issue:

Uncaught Error: [$injector:cdep] Circular dependency found: $http <- $templateFactory <- $view <- $state <- responseInterceptor <- $http <- $translateStaticFilesLoader

Code

(function() {
  'use strict';

  angular
    .module('app.core', ['ngAnimate',
      'ngSanitize',
      'ngResource',
      'ui.bootstrap',
      'ui.router.tabs',
      'scDateTime',
      'schemaForm',
      'ui.validate',
      'ngStorage',
      'ngMaterial',
      'pascalprecht.translate',
      'ui.router'
    ])
    .factory('responseInterceptor', responseInterceptor)
    .config(httpProviderConfig);

  responseInterceptor.$inject = ['$q', '$rootScope', '$state'];
  function responseInterceptor($q, $rootScope, $state){
    return {
      responseError: function(response) {
        $rootScope.showSpinner = false;
        if(response.status === 401){
          $state.go('login');
        }
        return $q.reject(response);

      }
    }
  }

  httpProviderConfig.$inject = ['$httpProvider'];
  function httpProviderConfig($httpProvider){
    $httpProvider.interceptors.push('responseInterceptor');
  }
})();

I can solve this using $injector.get() to retrieve an instance instead:

  responseInterceptor.$inject = ['$q', '$rootScope', '$injector'];
  function responseInterceptor($q, $rootScope, $injector){
    return {
      responseError: function(response) {
        $rootScope.showSpinner = false;
        if(response.status === 401){
          $injector.get('$state').go('login');
        }
        return $q.reject(response);

      }
    }
  }

Whilst this works, I would rather try and get to the bottom of the problem.

Judging by the error, I think this is being caused by the following config on my app.core module

(function() {
  'use strict';

  angular.module('app.core').config(translateProviderConfig);

  translateProviderConfig.$inject = ['$translateProvider'];

  function translateProviderConfig($translateProvider) {
    $translateProvider.useStaticFilesLoader({
      prefix: 'assets/locale/',
      suffix: '.json'
    });
    $translateProvider.preferredLanguage('en_gb');
    return $translateProvider.useSanitizeValueStrategy('sanitize');
  }
})();

So I'm unsure what to do next, is it valid to use $injector.get() or does this indicate a problem else where in the way I am including dependencies, e.g. duplicates?

1
$injector.get() is the way - Dave Bush
Ok, care to elaborate? - mindparse
Happy to help. What more were you looking for? Sometimes, this is the only way to resolve a circular reference. - Dave Bush
It's just that the solution feels somewhat of a hack, I have seen plenty of other posts suggesting the same approach, I just don't want to be introducing workaround code if instead the structure of my application needs attention. But if the general consensus is that this is the angular way, then so be it. - mindparse

1 Answers

1
votes

If you can re-architect the code to avoid it, you should. However, if I read your code correctly, you are injecting at a point when it is nearly impossible to avoid a circular reference. In fact, the first time I found this "hack" was when I was doing something very similar. (Putting up a wait state during http calls.)

The only caveat I would mention is that you'll need to do the $inject.get() in the method that needs it rather than in the constructor of the object the method is in or you will continue to get the circular reference.