use $http inside custom provider in app config, angular.js

JavascriptAngularjsAngular Services

Javascript Problem Overview


The main question - is it possible? I tried with no luck..

main app.js

...
var app = angular.module('myApp', ['services']);
app.config(['customProvider', function (customProvider) {

}]);
...

provider itself

var services = angular.module('services', []);
services.provider('custom', function ($http) {
});

And I've got such error:

Uncaught Error: Unknown provider: $http from services 

Any ideas?

Thanks!

Javascript Solutions


Solution 1 - Javascript

#The bottom line is:#

  • You CANNOT inject a service into the provider configuration section.
  • You CAN inject a service into the section which initializes the provider's service.

#Details:# Angular framework has a 2 phase initialization process:

###PHASE 1: Config### During the config phase all of the providers are initialized and all of the config sections are executed. The config sections may contain code which configures the provider objects and therefore they can be injected with provider objects. However, since the providers are the factories for the service objects and at this stage the providers are not fully initialized/configured -> you cannot ask the provider to create a service for you at this stage -> at the configuration stage you cannot use/inject services. When this phase is completed all of the providers are ready (no more provider configuration can be done after the configuration phase is completed).

###PHASE 2: Run### During run phase all the run sections are executed. At this stage the providers are ready and can create services -> during run phase you can use/inject services.

#Examples:#

###1. Injecting the $http service to the provider initialization function WILL NOT work###

> //ERRONEOUS > angular.module('myModule').provider('myProvider', function($http) { // SECTION 1: code to initialize/configure the PROVIDER goes here (executed during config phase) ...

> this.$get = function() { // code to initialize/configure the SERVICE goes here (executed during run stage)

> return myService; }; });

Since we are trying to inject the $http service into a function which is executed during the config phase we will get an error:

> Uncaught Error: Unknown provider: $http from services

What this error is actually saying is that the $httpProvider which is used to create the $http service is not ready yet (since we are still in the config phase).

###2. Injecting the $http service to the service initialization function WILL work:###

//OK
angular.module('myModule').provider('myProvider', function() {
    // SECTION 1: code to initialize/configure the PROVIDER goes here (executed during `config` phase)
    ...

    this.$get = function($http) {
        // code to initialize/configure the SERVICE goes here (executed during `run` stage)
        
        return myService;
    };
});

Since we are now injecting the service into the service initialization function, which is executed during run phase this code will work.

Solution 2 - Javascript

This might give you a little leverage:

var initInjector = angular.injector(['ng']);
var $http = initInjector.get('$http');

But be careful, the success/error callbacks might keep you in a race-condition between the app start and the server response.

Solution 3 - Javascript

This is an old question, seems we have some chicken egg thing going on if we want to rely on the core capability of the library.

Instead of solving the problem in a fundamental way, what I did is by-pass. Create a directive that wraps the whole body. Ex.

<body ng-app="app">
  <div mc-body>
    Hello World
  </div>
</body>

Now mc-body needs to be initialized before rendering (once), ex.

link: function(scope, element, attrs) {
  Auth.login().then() ...
}

Auth is a service or provider, ex.

.provider('Auth', function() {
  ... keep your auth configurations
  return {
    $get: function($http) {
      return {
        login: function() {
          ... do something about the http
        }
      }
    }
  }
})

Seems to me that I do have control on the order of the bootstrap, it is after the regular bootstrap resolves all provider configuration and then try to initialize mc-body directive.

And this directive seems to me can be ahead of routing, because routing is also injected via a directive ex. <ui-route />. But I can be wrong on this. Needs some more investigation.

Solution 4 - Javascript

In response to your question, "Any Ideas?", I would have respond with "yes". But wait, there's more!

I suggest just using JQuery in the config. For example:

var app = angular.module('myApp', ['services']);
app.config(['$anyProvider', function ($anyProvider) {
    $.ajax({
        url: 'www.something.com/api/lolol',
        success: function (result) {
            $anyProvider.doSomething(result);
        }
    });
}]);

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionKosmetikaView Question on Stackoverflow
Solution 1 - JavascriptDana ShalevView Answer on Stackoverflow
Solution 2 - JavascriptCodyView Answer on Stackoverflow
Solution 3 - JavascriptwindmaomaoView Answer on Stackoverflow
Solution 4 - JavascriptSuamereView Answer on Stackoverflow