75

In Angular, we can inject $routeProvider to the config function

module.config(function ($routeProvider) {


});

I want to inject my service into it like

module.config(function ($routeProvider, myService) {


});

I am sure the service is defined properly, but it throws an exception saying that unknown myService, event when I inject like

module.config(function ($routeProvider, $http) {


});

it still says unknown $http.

Do you know why?

danwellman
  • 9,068
  • 8
  • 60
  • 88
Fred Yang
  • 2,521
  • 3
  • 21
  • 29
  • you can inject `$http` for configuration only ie as `$httpProvider`: https://docs.angularjs.org/api/ng/provider/$httpProvider – dewd May 09 '16 at 09:51

7 Answers7

94

From Modules page, section "Module Loading & Dependencies":

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.

Run blocks - get executed after the injector is created and are used to kickstart the application. Only instances and constants can be injected into run blocks. This is to prevent further system configuration during application run time.

So you can't inject your own service, or built-in services like $http into config(). Use run() instead.

Community
  • 1
  • 1
Mark Rajcok
  • 362,217
  • 114
  • 495
  • 492
  • Thanks for answer, but why $routeProvider can be injected into the config function, is this the only dependency which can be injected into the config function? I doubt it. – Fred Yang Mar 09 '13 at 17:55
  • 2
    As stated, any "provider" (Angular built-in, or your own) or "constant" can be injected into the config() function. Here is some Angular source code that contains the built-in providers: https://github.com/angular/angular.js/blob/79b51d5b578927bd510123c81953e7cc8c72f211/src/AngularPublic.js – Mark Rajcok Mar 09 '13 at 18:07
58

I don't have enough reputation to post a comment, but wanted to add to Mark's answer.

You can register providers yourself. They are basically objects (or constructors) with a $get method. When you register a provider the standard version of it can be used like a service or factory, but a provider version can be used earlier. So a grumpy provider that is registered as

angular.module('...', [])
    .provider('grumpy', GrumpyProviderObject)

is then available in the config function as

    .config(['grumpyProvider', ..., function (grumpyProvider, ...) { ... }])

and can be injected into controllers simply as

    .controller('myController', ['grumpy', ..., function (grumpy, ...) { ... }])

The grumpy object that is injected into myController is simply the result of running the $get method on the GrumpyProviderObject. Note, the provider you register can also be a regular JavaScript constructor.

Note: as per the comment by @Problematic, that the provider initialization (the call to angular.module().provider(…) must come before the config function to be available.

Jonas Rabbe
  • 2,175
  • 1
  • 16
  • 14
  • 4
    Thanks for this. It's worth noting that the config function must come after the provider to inject it. Might be obvious, but it tripped me up! – Problematic Aug 22 '13 at 20:07
  • 1
    Thank you for this. I now see that the provider itself must be without the postfix 'Provider'. My config was looking for ProviderProvider which it could not find. – Etienne Marais Sep 23 '13 at 07:29
  • 2
    This will also work with `constant`s, because constants are also providers. – Patrick Hillert Jun 22 '15 at 08:15
10

You can do it like this:

(function() {
    'use strict';

    angular.module('name', name).config(config);
    // You can do this:
    config.$inject = ['$routeProvider', 'myService'];

    function config($routeProvider, myService) {
        // Or better to use this, but you need to use ng-annotate:
        /* ngInject */

    }
});

It is best practice that is described here

Alexander Zeitler
  • 11,919
  • 11
  • 81
  • 124
Lyubimov Roman
  • 1,269
  • 15
  • 27
  • Why? I did it recently. – Lyubimov Roman Aug 17 '15 at 09:21
  • 1
    @DanielKobe .config('config', config); should be .config(config); – m1kael Nov 04 '15 at 00:59
  • Yeah, my mistake, I have edited the answer. I was confused services with simple configuration. Configs are not injected as services do. – Lyubimov Roman Nov 09 '15 at 09:28
  • Haven't tried it, but this should not work. It's only another way to try to inject a service in a config-section. If it works, it's a bug in Angular. – hgoebl Dec 31 '15 at 12:15
  • Why it shouldn't work? $inject it is true way to inject services and other things in angular. Why config can't work like this if e.g. controller can. – Lyubimov Roman Dec 31 '15 at 16:03
  • @FriOne where in John Papa's bible is this described? I can't seem to find it. Actually, I just did find it. It's now here: https://github.com/johnpapa/angular-styleguide/blob/master/a1/README.md#style-y091 – Mike Feltman Mar 10 '16 at 16:32
  • @MikeFeltman e.g. https://github.com/johnpapa/angular-styleguide/blob/master/a1/README.md#style-y060 But better to use /*ngInject*/ – Lyubimov Roman Mar 10 '16 at 17:12
  • 3
    This shouldn't work, I curious why so many upvotes? see here `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.` – Saorikido Jan 16 '17 at 07:43
  • No way this works. You can not inject one of your services into the configuration block as your services aren't guaranteed to be configurated for use yet. As the comment above mentions... only Providers and constants are allowed for injection into a configuration block. – Steven Rogers Feb 28 '17 at 15:59
  • So if a service doesn't have configuration it is ok? I know this thing works. What if you have helper service that help you to configurate another service? Why is it so bad? You simly separete a logic. – Lyubimov Roman Feb 28 '17 at 16:03
5

You can manually call angular.injector to gain access to services which don't have dependencies during the .config() block of your app. If the service you created doesn't have any dependencies which need to be traversed, then you can probably use this:

angular.module('myApp').config(function () {
    var myService = angular.injector(['ng']).get('myService');
});

This works for other simple services like $http as well:

angular.module('myApp').config(function () {
    var http = angular.injector(['ng']).get('$http');
});

Note: Usually you shouldn't need to inject services during your config phase, it's better design to create a provider that allows for configuration. The docs say this functionality is exposed for cases where 3rd party libraries need to get access to the injector of an already-running Angular app.

Alex Ross
  • 3,729
  • 3
  • 26
  • 26
  • I tried this with $location but that one doesn't work. Gives a "Unknown provider: $rootElementProvider" error message. – AndrewR Jan 06 '16 at 03:07
  • 2
    When you call [`$injector.get('serviceName')`](https://docs.angularjs.org/api/auto/service/$injector#get) on a service that hasn't been instantiated yet (like in the `.config()` block), the injector tries to instantiate that service on the spot. If that service has any dependencies, it'll throw an error because those deps are missing. Unfortunately you can't provide the dependencies when you call `.get()`. `$location` [has a dependency](https://github.com/angular/angular.js/blob/master/src/ng/location.js#L671) on `$rootElement`, so it can't be loaded in this way. – Alex Ross Jan 07 '16 at 00:08
4

If you want to inject dependency (let's say from a Service) to call a function form in routes (.config) as shown below templateProvider.getTemplate('about')

.state('index.about', {  

    url: "/about",  
    templateUrl: templateProvider.getTemplate('about'),  
    controller: 'AboutCtrl',  
    controllerAs: 'about',  
    data: {pageTitle: 'About Us Page'}  

})  

You must create a Provider. Not Service nor Factory.

Here’s a real example of a Provider that generates the template path from the name:

(function () {  

    'use strict';  
    angular  

        .module('mega-app')  

        .provider('template', provider);  

      function provider(CONSTANT) {  

        // The provider must include a $get() method This $get() method  
        // will be invoked using $injector.invoke() and can therefore use  
        // dependency-injection.  
       this.$get = function () {  

            return {}  

        };  
       /**  
         * generates template path from it's name  
         *  
         * @param name  
         * @returns {string}  
         */  
       this.getTemplate = function (name) {  

            return CONSTANT.TEMPLATES_URL + name + '/' + name + '.html';  
        }  


        /**  
         * generates component path from it's name  
         * @param name  
         * @returns {string}  
         */  
       this.getComponent = function (name) {  

            return CONSTANT.COMPONENTS_URL + name + '.html';  
        }  

    };  
})();  

The usage of such Provider in the routes (.config) will be as follow:

(function () {  

    'use strict';  
    angular  

        .module('mega-app')  

        .config(routes);  
   function routes($stateProvider, $urlRouterProvider, templateProvider) {  



       $stateProvider  
            //----------------------------------------------------------------  
            // First State  
            //----------------------------------------------------------------  
            .state('index', {  

                abstract: true,  
                url: "/index",  
                templateUrl: templateProvider.getComponent('content'),  
                controller: 'IndexCtrl',  
                controllerAs: 'index',  
            })  

            //----------------------------------------------------------------  
            // State  
            //----------------------------------------------------------------  
            .state('index.home', {  

                url: "/home",  
                templateUrl: templateProvider.getTemplate('home'),  
                controller: 'HomeCtrl',  
                controllerAs: 'home',  
                data: {pageTitle: 'Home Page'}  

            })  

            //----------------------------------------------------------------  
            // State  
            //----------------------------------------------------------------  
            .state('index.about', {  

                url: "/about",  
                templateUrl: templateProvider.getTemplate('about'),  
                controller: 'AboutCtrl',  
                controllerAs: 'about',  
                data: {pageTitle: 'About Us Page'}  

            })  

        //----------------------------------------------------------------  
        // Default State  
        //----------------------------------------------------------------  
       $urlRouterProvider.otherwise('/index/home');  
    };  
})();  

VIP Note:

to inject the provider you must postfix it with xxxProvider (that name of the provider should not be postfixed, only on injection in the .config).

Mahmoud Zalt
  • 30,478
  • 7
  • 87
  • 83
  • I want to do $http call in my config, and fetch some json file, which contains website languages, and then pass them to language configuration.... everyone talk about $get but the $get seem to not get runned on it's own, can you provide more information, so if this provider should replace the config file, it does, and if it has some way to call the $http and etc later, do that instead? – Hassan Faghihi Nov 21 '18 at 13:13
-2

If it can make things easier for some of you.

Per explained in this answer, you can just append Provider to your custom service and then access the internal functions using $get().

It may not be the cleanest solution, but it does the job.

module.config(function ($routeProvider, myServiceProvider) {
 // Call a function hello() on myService.
 myServiceProvider.$get().hello();
});
Community
  • 1
  • 1
Andrew
  • 7,848
  • 1
  • 26
  • 24
  • Uncaught TypeError: $locationProvider.$get is not a function(…) – Gary Aug 09 '16 at 14:40
  • Hi, you should be able to use the `$locationProvider` as it is. It's already a provider. No need to use the `$get()` hack. Am I missing something? – Andrew Aug 09 '16 at 14:45
  • It doesn't have .path or anything, just .$get as an Array[6], hashPrefix function, and html5Mode function. I'm $injecting '$locationProvider' into the config like $routeProvider. – Gary Aug 09 '16 at 14:57
-15

You could try this:

module.config(['$routeProvider', '$http', function ($routeProvider, $http) {}]);
Steven Beaupré
  • 21,343
  • 7
  • 57
  • 77
Hunter
  • 11
  • Only Providers and constants are allowed in config blocks for injection. Services are not ready until *after* the configuration block is executed. – Steven Rogers Feb 28 '17 at 16:08