0

Similar question here but doesn't appear to work in this case. I'm using Angular-UI's Google Maps API, which requires configuration like so:

.config(function(uiGmapGoogleMapApiProvider) {
    uiGmapGoogleMapApiProvider.configure({
        //    key: 'your api key',
        v: '3.20', //defaults to latest 3.X anyhow
        libraries: 'weather,geometry,visualization'
    });
})

I don't want to have my API key directly in here, I'd like to load it in from my server using a route via a GET request ('/api/googleAPI'). However, when I try:

 .config(function($http, uiGmapGoogleMapApiProvider) {

I get:

 Failed to instantiate module myApp due to: Error: [$injector:unpr] Unknown provider: $http

Are there any workarounds for this or should I just brazenly chuck my API key in here?

Community
  • 1
  • 1
JVG
  • 20,198
  • 47
  • 132
  • 210

2 Answers2

1

Are there any workarounds for this or should I just brazenly chuck my API key in here?

No don't put your API key in there, there are workarounds.


There are 2 basic phases for angular when it's loading/injecting/setting up dependencies. There is the config phase and then there is the post-config phase. (These aren't official names of phases, it's just how I describe them).

config phase

In the config phase, the only things that are available for injection are -Providers type constructs. This means that anything you typically inject inside a service or a controller aren't available for injection in your configuration function.

post-config phase

Once you're application has been bootstrapped, configured, etc., then you can inject your typical injectable dependencies (e.g. $http, $q, $templateCache, etc.)

typical solution

So in order to solve your issue, what I suggest is if you can't leverage something like module.run( function($http){ $http.get(<url to your config>) }) then you need to maybe forgo using $http and use a standard XMLHttpRequest for this bit of logic.

atypical solution

In the app I am working on, we have a similar need to load up some non-angular config data via a .txt file. Here's what I've done:

First postpone the automatic angular bootstrapping process (meaning I've left out the typical ng-app in my main index file). Then load the .txt file via:

var client = new XMLHttpRequest();
client.open( 'GET', './version.txt' );
client.onload = function()
{
    kickoffAngular(client.responseText)
}
client.send();

Assuming your text is something simple like a key/value pair, each pair on a newline, you can parse the responseText like so:

kickoffAngular = function(text){
   var kvPairs = text.split('\n')
   kvPairs.forEach(function(kv){
       var pair = kv.split('=')
       var key = pair[0]
       var val = pair[1]
       ... do something with them
   })
}

Then bootstrap Angular via:

angular.bootstrap( document, <app name> )
jusopi
  • 6,791
  • 2
  • 33
  • 44
  • Great answer, thanks for the detail. Do you have any suggested resources for doing the XMLHttpRequest? SO is a bit of a quagmire here and everything I've seen seems super convoluted for something so simple... – JVG Jan 07 '16 at 18:06
  • 1
    `client.responseText` will be the contents of your XMLHttpRequest response. You can access that in the `onLoad` function to get what you need. I will update the answer to reflect that. – jusopi Jan 07 '16 at 18:14
  • 2
    You can probably stay way from using `XMLHttpRequest` by using the `angular.injector()` method. See this **[article](https://blog.mariusschulz.com/2014/10/22/asynchronously-bootstrapping-angularjs-applications-with-server-side-data)**. – ryeballar Jan 07 '16 at 18:15
  • @ryeballar I actually like your link's solution for the pre-bootstrapping process, it would be nice to be able to leverage angular's $http & $q services prior to bootstrapping the app. Thanks. – jusopi Jan 07 '16 at 18:22
1

based on @ryeballar's suggestion

After reading the link that @ryeballer provided in the comments for my other answer, there is a much simpler workaround that doesn't require you to mess with the pre-bootstrapping processing or XMLHttpRequests or anything suggested in the atypical solution above.

.config(function(uiGmapGoogleMapApiProvider) {

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

    $http.get(<url to your key>)
    .then(function(rsp){
        var data = rsp;
        uiGmapGoogleMapApiProvider.configure({
            key: data.key,
            v: '3.20', //defaults to latest 3.X anyhow
            libraries: 'weather,geometry,visualization'
        })
     })
})

I'd argue that this should probably be the selected answer given it's simplicity and that it operates within the typical angular post-bootstrapping lifecycle

Community
  • 1
  • 1
jusopi
  • 6,791
  • 2
  • 33
  • 44
  • This is nice, but unlike the other solution it runs asynchronously. That's either a feature or a problem, depending on what the developer needs this initialization for. – Bampfer Oct 30 '17 at 14:16