33

Is it possible to do DI in a provider method?

In this example

angular.module('greet',[])
.provider('greeter',function() {

  this.$get=function() {

  };
})
.service('greeterService',function($http){
  console.log($http);
})
;

Injecting $http into service appears to be the correct implementation, but it doesn't work in a provider method and it throws an error:

Unknown provider: $http

Does the provider method work with DI to inject services?

Gonzalo.-
  • 12,512
  • 5
  • 50
  • 82
Chung
  • 1,063
  • 1
  • 13
  • 21

5 Answers5

60

You can certainly inject $http to provider. Just make sure it appears in $get, not the function constructor. As follows:

angular.module('greet',[]).provider('greeter',function() {
  this.$get = function($http) {

  };
});
Buu
  • 49,745
  • 5
  • 67
  • 85
  • 1
    Thanks. Does it mean we can't use $http(or other services) outside of $get? – Chung Oct 04 '13 at 04:21
  • No, you can use $http anywhere that a service can be injected. $get is just one of them. – Buu Oct 04 '13 at 05:51
  • 14
    The Provider docs have a minification safe example (https://docs.angularjs.org/guide/providers). `this.$get = ["apiToken", function unicornLauncherFactory(apiToken) { return new UnicornLauncher(apiToken); }];` – AndrewS Jun 12 '14 at 02:12
  • 3
    WTF moment of the day for me :) – Ярослав Рахматуллин Jul 24 '14 at 10:39
  • Here's a [plunk](http://plnkr.co/edit/ZDkmcAlNXaa168iudNSH?p=preview) showing provider injecting a service (different modules). The `$injector` fetches service dependencies from the contstructor arguments. (See the $route module's usage of $injector to see how this can be done dynamically *ala* resolve) – deck Sep 02 '14 at 16:45
  • I can inject $resource ` $get: function($resource){}` – Emeka Mbah Mar 29 '16 at 12:54
13

You can inject constants and other providers into a provider. Not services or factories - with one exception. It seems that you can inject the $injector service into a provider - at least, you can in AngularJS 1.3.16.

.provider('foo', ['$injector', function ($injector) {
  var messagePrefix = $injector.get('msgPrefix');
  this.message = '';

  this.$get = function() {
    var that = this;
    return function() {
      return messagePrefix + that.message;
    }
  };
}])

You can use the injector outside the $get method, but you still can't get services from it at configure time.

See here for a demo.

z0r
  • 8,185
  • 4
  • 64
  • 83
7

Following up on IgrCndd's answer, here's a pattern that might avoid potential nastiness:

angular.module('greet',[]).provider('greeter', function() {

    var $http;

    function logIt() {
        console.log($http);
    }

    this.$get = ['$http', function(_$http_) {
        $http = _$http_;

        return {
            logIt: logIt
        };
    }];
});

Note how similar this is to the equivalent service, making conversion between the two less troublesome:

angular.module('greet',[]).factory('greeter', ['$http', function($http) {

    function logIt() {
        console.log($http);
    }

    return {
        logIt: logIt
    };
});
Dunc
  • 18,404
  • 6
  • 86
  • 103
3

You actually have to inject the dependency on $get and then store it to use on what you retrieve from $get. Not beautiful at all...

IgrCndd
  • 53
  • 4
3

No, you can not inject a service into the provider itself. Injecting a service into a provider's $get method is the same as injecting a service into a factory, but you can not inject it into the provider function directly.

The difference between $get and the provider itself is that the provider runs during the module loading phase whereas the $get is run when instantiating the service you are providing.

This implies that you can not use any service at all during the module loading/configuration phase of your modules. That is all the stuff you run inside your config blocks, such as when defining your app routes or states, can not make use of any service.

The only other thing you can inject into config blocks besides providers are constants.

You could do something like IgrCndd suggested. But if you needed to consume the provider in a config block, which is the provider's purpose after all, you will not have your values injected until much after. So it's not going to work unless you do some nasty hack using promises.

Further reading on injectables

Community
  • 1
  • 1
Jens
  • 5,767
  • 5
  • 54
  • 69