Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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

like image 272
Lior Avatar asked Mar 27 '13 15:03

Lior


2 Answers

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.

like image 167
diegovilar Avatar answered Oct 10 '22 10:10

diegovilar


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.

like image 31
Lior Avatar answered Oct 10 '22 09:10

Lior