简体   繁体   中英

Using `$mdToast` inside an interceptor triggering circular dependency

Question:

How can I use $mdToast inside an interceptor without triggering the error?

Setup:

Interceptor definition:

(function () {
  'use strict';

  angular
    .module('app.components.http-errors-interceptors')
    .factory('HttpError500Interceptor', HttpError500Interceptor);

  /* @ngInject */
  function HttpError500Interceptor($q,
                                   $mdToast,
                                   $filter) {

    var interceptor           = {};
    interceptor.responseError = responseError;

    function responseError(responseError) {
      if (responseError.status === 500) {
        $mdToast.show($mdToast.simple()
                              .content($filter('translate')('APP.COMPONENTS.HTTP_ERRORS_INTERCEPTORS.500'))
                              .position('bottom right')
                              .hideDelay(5000));
      }
      return $q.reject(responseError);
    }

    return interceptor;
  }
})();

Interceptor config:

(function () {
  'use strict';

  angular
    .module('app.components.http-errors-interceptors')
    .config(moduleConfig);

  /* @ngInject */
  function moduleConfig($httpProvider) {
    $httpProvider.interceptors.push('HttpError500Interceptor');
  }
})();

Issue:

When I load the application it triggers the following error:

Uncaught Error: [$injector:cdep] Circular dependency found: $http <- $templateRequest <- $$animateQueue <- $animate <- $$interimElement <- $mdToast <- HttpError500Interceptor <- $http <- $templateFactory <- $view <- $state

One work around that has helped me in the past is to use $injector to get your dependency at runtime instead of at configuration time. So, something like:

  /* @ngInject */
  function HttpError500Interceptor($q,
                                   $injector,
                                   $filter) {
    function responseError(responseError) {
      var $mdToast = $injector.get('$mdToast');

When your cyclic dependency does not cause problems, which it probably doesn't in this case, this will do the trick.

Neither of the provided solutions worked for me, so I'm posting here what I did so anyone with the same issue can have a range of workarounds to use.

What I really wanted was to have a common component to handle HTTP interceptors named interceptors and show the messages directly from the module, and happily, since the final solution is more elegant, it triggered this error while injecting the $mdToast service.

The solution I came later, which I already said, is more elegant that my first fix to the issue is:

  • to have a common component to handle HTTP interceptors named interceptors ,
  • to have a common component to handle global notifications named notifications-hub .

Then, in the interceptors module, I trigger a global event with:

$rootScope.$broadcast('notifications:httpError', responseError);

Then, in the notifications-hub module, I registered on the event and used the $mdToast , which was injected without errors in the notifications service:

$rootScope.$on('notifications:httpError', function (event, responseError) { NotificationsHubService.processErrorsAndShowToast(responseError); });

NotificationsHubService is the service injecting $mdToast .

Conclusion:

I used a global event as a glue between the low-level interceptors and the notifications subsystem to overcome the issue.

Hopefully it will be of use for anyone else.

What you should do is create a function that brings you the toaster at run time

  var getToaster = ()=>{

    var toaster = $injector.get('$mdToaster');
    return toaster;
}

Now call it only when you need it - this will provide a work around the dependency circular

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM