0

Given the following, $injector.get will fail as $rootScope is not available.

app.factory('$exceptionHandler', ['$injector', $injector => {
  const $rootScope = $injector.get('$rootScope')

  return (exception, cause) => {
    // code
  }
})

In researching, I keep coming across this, which works as it's resolved at runtime (when the inner function is called).

app.factory('$exceptionHandler', ['$injector', $injector => {
  return (exception, cause) => {
    const $rootScope = $injector.get('$rootScope')
    // code
  }
})

What I'd like is to somehow know when I can resolve the dependency. Something like:

app.factory('$exceptionHandler', ['$injector', $injector => {
  $injector.illLetYouKnowWhenWeCanDoStuff().then(() => {
    const $rootScope = $injector.get('$rootScope')
  })

  return (exception, cause) => {
    // code
  }
})

Is this possible?

related => $location from $exceptionHandler - dependency conflict

aw04
  • 10,857
  • 10
  • 56
  • 89
  • Why do you inject the injector, instead of just injecting $rootScope in the first place? The injector would figure out the dependency, and thus create the $rootScope and inject it before creating your exceptionHandler. Also, note that the `$` prefix is precisely there to distinguish between angular services and your own services. So you shouldn't prefix your services with `$`. – JB Nizet Sep 26 '17 at 15:15
  • @JBNizet read the q&a I've linked to at the bottom, and what service of mine are you referring to? the local $rootScope? – aw04 Sep 26 '17 at 15:20
  • @JBNizet $injector is required for the second example to work (and my current workaround) but it's probably irrelevant in the first example (same error either way) – aw04 Sep 26 '17 at 15:21
  • Ordinarily, all injectables that will ever be are available once the app bootstraps. New services are not generally added at runtime. Maybe if you explain at a higher level what you're trying to achieve, someone can help. – JC Ford Sep 26 '17 at 15:23
  • @JCFord Sure. I just need to get something from $rootScope inside this factory. Problem is it's not ready initially but I can get it after some period of time (ie inner function) – aw04 Sep 26 '17 at 15:24
  • Not ready initially why? Loaded from asynchronously? From $http perhaps? – JC Ford Sep 26 '17 at 15:25
  • One thing you might consider is using `$rootScope.$broadcast` or `$scope.$emit` to send notification once your data is available. – JC Ford Sep 26 '17 at 15:26
  • @JCFord You can read the q&a I've linked to for an example of the problem, I'll admit I'm not exactly sure why it happens (though I get the same circular dependency) – aw04 Sep 26 '17 at 15:27
  • @JCFord right but I need to be able to inject $rootScope – aw04 Sep 26 '17 at 15:27
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/155348/discussion-between-jc-ford-and-aw04). – JC Ford Sep 26 '17 at 15:29

1 Answers1

1

All injectables registered through normal angular functions (factory, service, controller, etc) are available right away at bootstrap. $rootScope isn't registered normally. It's provided after the app bootstraps. Because $exceptionHandler is instantiated right away, $rootScope isn't available yet.

The best way to get around a circular dependency error is to break the circle. Let your $exceptionHandler depend on a custom service you build. Configure that new service in a .run() block into which $rootScope is injected.

app.factory('$exceptionHandler', ['myExceptionHandlingConfig', function(myExceptionHandlingConfig) {

  return function(exception, cause) {
    //do exceptional stuff
  }

}]);

app.factory('myExceptionHandlingConfig', function() {

  return {};

});

app.run(['$rootScope', 'myExceptionHandlingConfig', function($rootScope, myExceptionHandlingConfig){

  myExceptionHandlingConfig.someProperty = $rootScope.something;

}]);

Note: $rootScope will be pretty empty at bootstrap time, so you might want to set a $watch to update the service when whatever data you're looking for is available.

JC Ford
  • 6,946
  • 3
  • 25
  • 34