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?

1

7 Answers 7

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.

Sign up to request clarification or add additional context in comments.

2 Comments

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.
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: github.com/angular/angular.js/blob/…
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.

3 Comments

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!
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.
This will also work with constants, because constants are also providers.
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

10 Comments

Why? I did it recently.
@DanielKobe .config('config', config); should be .config(config);
Yeah, my mistake, I have edited the answer. I was confused services with simple configuration. Configs are not injected as services do.
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.
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.
|
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.

2 Comments

I tried this with $location but that one doesn't work. Gives a "Unknown provider: $rootElementProvider" error message.
When you call $injector.get('serviceName') 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 on $rootElement, so it can't be loaded in this way.
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).

1 Comment

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?
-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();
});

3 Comments

Uncaught TypeError: $locationProvider.$get is not a function(…)
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?
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.
-15

You could try this:

module.config(['$routeProvider', '$http', function ($routeProvider, $http) {}]);

1 Comment

Only Providers and constants are allowed in config blocks for injection. Services are not ready until after the configuration block is executed.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.