Angular JS: why the difference between module.config injection and controller injection?

All we need is an easy explanation of the problem, so here it is.

This is something that I could not figure out from digging into the AngularJS code, maybe you can help solve the mystery.

To show it, I added a service to AngularJS seed project:

function MyServiceProvider() {
    console.log('its my service');
    this.providerMethod = providerMethod;

    function providerMethod() {
        console.log('its my service.providerMethod');
    }

    this.$get = $get;

    function $get() {
        var innerInjectable = {
             name: 'stam'
        };
        return innerInjectable;
    }
}

var serviceModule = angular.module('myApp.services', []).
    value('version', '0.1').
    provider('myservice',MyServiceProvider);

You can see that this provider exposes $get and a certain ‘providerMethod’.

Now, for the injection usage:
If we call config, we can inject the whole class and get access to the ‘outer’ provider method:

serviceModule.config(function(myserviceProvider) {
    console.log('myServiceProvider:',myserviceProvider);
    myserviceProvider.providerMethod();
});

But when we inject this to a controller (note the Provider-less name), only the $get return value is exposed:

function MyCtrl1(myservice) {
    console.log('MyCtrl1.myservice =',myservice,myservice.name);
}
MyCtrl1.$inject = ['myservice'];

Console output follows as it should:
its my service
myServiceProvider:
Constructor {providerMethod: function, $get: function}
its my service.providerMethod
MyCtrl1.myservice = Object {name: “stam”} stam

Can any one explain the difference? The reason?
many thanks for any thought

Lior

PS: I’ve seen this technique in angular-ui new ui-router (excellent project!). I need access to the outer provider class to do injection in jasmine and other places – to no avail

How to solve :

I know you bored from this bug, So we are here to help you! Take a deep breath and look at the explanation of your problem. We have many solutions to this problem, But we recommend you to use the first method because it is tested & true method that will 100% work for you.

Method 1

A provider is responsible for creating instances. In your example, you created a provider explicitly, but the truth is that every service has a provider, even if it’s created automatically for it. [module].service() and [module].factory() are just shortcuts for [module].provider().

[module].config() is run during provider registrations and configurations so you get a change to access providers and do stuff with them. It’s a place for configuration of things, hence the name.

From the documentation (http://docs.angularjs.org/guide/module):

Configuration blocks – get executed during the provider registrations
and configuration phase. Only providers and constants can be injected
into configuration blocks. This is to prevent accidental instantiation
of services before they have been fully configured.

Controllers, in the other hand, are instantiated AFTER services have been configured, so you’re not supposed to mess with providers anymore. Everything has already been configured. You’re ready to get their products now. In this phase, the injector just can’t inject providers anymore, just instances (services) created by them.

If you register a service myService

myModule.service('myService', function() {
    // this is your service constructor
});

then you can access its provider, myServiceProvider, in a config function…

myModule.config(function(myServiceProvider) {
    // to stuff with your provider here
});

but by the time controllers are being instantiated, you’re supposed to ask for services, not their providers, so this will not work…

myModule.controller(function(myServiceProvider) {
    ...
});

whereas this will be fine…

myModule.controller(function(myService) {
    ...
});

If you’re finding yourself needing to do configuration in a controller, you should stop and rethink the place of responsibilities.

Method 2

From the Angular mailing list I got an amazing thread that explains service vs factory vs provider and their injection usage. I decided to put it in its own question here

the specific answer is: it is so by design, to allow configuration of the provider at config time.

Note: Use and implement method 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply