I have the google api key in a singleton configuration service (a way to share the app configuration accross all the application).
How can I pass the apiKey variable the module inside @NgModule?
`@NgModule({
imports: [
BrowserModule,
CommonModule,
FormsModule,
AgmCoreModule.forRoot({
apiKey: 'YOUR_KEY' // <-- I cannot use a constant!!! How can I pass a variable?
})
],
providers: [],
declarations: [ AppComponent ],
bootstrap: [ AppComponent ]
})`
Depends on what kind of build tool you are using (e.g. angular-cli or custom webpack or ...) and where the variable should come from.
This can be a little tricky. Specially when you also want to use AOT compiling, which prevents too much dynamic code inside the @NgModule
.
The solution I currently implemented is overriding the 'lazy config provider' in my main app.module.
In the module where I actually use the map, I use an empty config in the forRoot:
AgmCoreModule.forRoot()
In my app.module.ts:
import the injection token:
import { LAZY_MAPS_API_CONFIG }
from 'angular2-google-maps/core/services';
Add to providers in @NgModule
:
providers: [
{provide: LAZY_MAPS_API_CONFIG, useClass: GoogleMapsConfig}
],
And implement that 'GoogleMapsConfig' class, which should implement the LazyMapsAPILoaderConfigLiteral
interface (from ' from 'angular2-google-maps/core/services').
@Injectable()
class GoogleMapsConfig {
apiKey: string;
...
constructor() {
apiKey = getMyApiKeyFromSomewhere()
...
}
}
In that injectable I can inject other services and read the config from somewhere.
(e.g. if you use angular-cli you can import environments there). Or maybe read out the domain from the browser... or call an serverside API...
I just tried the above. It manages to circumvent AoT errors, but the API key isn't being passed to Google Maps – so it returns key missing error.
In my use case, I'm using the extended-define-webpack-plugin to add a compile-time global config settings (API keys that can change based on build type etc).
import { LAZY_MAPS_API_CONFIG, LazyMapsAPILoaderConfigLiteral } from 'angular2-google-maps/core/services';
@Injectable()
export class GoogleMapsConfig implements LazyMapsAPILoaderConfigLiteral {
apiKey: string = CONFIG.googleMapsAPIKey;
}
@NgModule({
declarations: [...],
imports: [...],
providers: [{provide: LAZY_MAPS_API_CONFIG, useClass: GoogleMapsConfig}],
bootstrap: [AppComponent]
})
export class AppModule {}
And, in my lazy loaded module where I'm using the map, calling AgmCoreModule.forRoot()
I am using angular 4 and CLI 1.0.2, I am trying to get the above code by @kyranjamie but I cannot get this to work, what we are trying is basically the same set up a different key for prod vs. dev
this is my code, what am I doing wrong?
`
@Injectable()
export class GoogleMapsConfig implements LazyMapsAPILoaderConfigLiteral {
public apiKey: string;
constructor() {
if (environment.production) {
this.apiKey = KEY INSERTED HERE
};
}
}
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
FormsModule,
ReactiveFormsModule,
HttpModule,
AppRoutingModule,
NgbModule.forRoot(),
NouisliderModule,
AgmCoreModule.forRoot()
],
providers: [
{ provide: LAZY_MAPS_API_CONFIG, useClass: GoogleMapsConfig }
],
bootstrap: [AppComponent]
})
export class AppModule {
}
`
Are you sure that if (environment.production)
will ever resolve to true?
I have resolved this thanks for your feedback
@daBishMan or @kyranjamie , If you guys ever figured this out, could you post your final solution? @kyranjamie , my issue appears to be similar to yours,... on a product build where AOT is concerned, agm-map initialization in the request to maps.google.com,... no URL API-KEY parameter is being sent. Therefore, it comes back with "missing api key" errors.
@jorrit-wehelp, thank you for your guidance. I am including below what is working for me....
import {Injectable} from "@angular/core";
import {LazyMapsAPILoaderConfigLiteral} from "@agm/core";
import {Config} from "../providers/config";
@Injectable()
export class MapsConfig implements LazyMapsAPILoaderConfigLiteral{
public apiKey: string
public libraries: string[]
constructor(config: Config) {
this.apiKey = config.get("MAP_API_JS_KEY")
this.libraries = ['places']
console.log("lazy map init with " + this.apiKey)
}
}
in my main @ngmodule, I have this in providers...
{
provide: LAZY_MAPS_API_CONFIG,
useClass: MapsConfig,
deps: [Config]
}
The reference to the Config class is a build-time webpack variable-replace which setups of a map of variables used in Dev or Prod modes.
Hello
I was able to achieve the dynamic key, as by @jorrit-wehelp comments, but in my scenario after the user logout and loggedIn the agmKey value is not updating and not able to see the map
what I did was like in our module component we added the following code
So I moved the class GoogleMapsConfig
and {provide: LAZY_MAPS_API_CONFIG, useClass: GoogleMapsConfig}
inside map @component
```...
import { LAZY_MAPS_API_CONFIG , LazyMapsAPILoaderConfigLiteral} from '@agm/core';
import {AuthService} from '@pl-core/_services';
@Injectable();
class GoogleMapsConfig implements LazyMapsAPILoaderConfigLiteral {
public apiKey: string ;
constructor() {
console.log('INSIDE MAPs'); //This is not displayed in console
this.apiKey = _authService.currentUser() && _authService.currentUser().agmKey ? _authService.currentUser().agmKey : '';
_authService.getMapKey$.subscribe((key) => {
this.apiKey = key;
})
}
}
@Component({
selector: 'map-comp',
templateUrl: './dyn-map.component.html',
styleUrls: ['./dyn-map.component.scss'],
providers: [{provide: LAZY_MAPS_API_CONFIG, useClass: GoogleMapsConfig}],
encapsulation : ViewEncapsulation.None
})
```
after we logout and login with an other user the control is not coming inside the GoogleMapsConfig class what can I do to solve this issue??
I had @jorrit-wehelp's solution working but only intermittently because I had a race condition where my service that returns the api key would not always return it in time for the
constructor of my map component:
constructor(private envService: EnvironmentService) {
this.envService.environment$.subscribe(environment => {
// setTimeout is to wait a beat since my GoogleMapsConfig receives
// the key at the same instant.
setTimeout(() => this.gmapsApiKeyReady = true);
});
}
Then in the markup:
<agm-map *ngIf="gmapsApiKeyReady" ...></agm-map>
I don't know if this will apply to everyone or if this is more of a case by case basis, but I discovered this is the result of Angular's AOT compilation process, as opposed to an issue with agm itself. Here is an overview of the situation I had.
I wanted to make the API key config driven instead of a hard coded string, such that moving through different environments would allow me to use different API keys and monitor the API's usage. In order to do this, I had my .NET back-end inject some JavaScript with the value I needed into the global namespace, stored in Example.Namespace.GoogleMapsApiKey
. With that in mind, here was my TypeScript code.
// typings.d.ts
declare namespace Example.Namespace {
export const GoogleMapsApiKey: string;
}
// app.module.ts
import { AgmCoreModule } from "@agm/core";
import { NgModule } from "@angular/core";
@NgModule({
// ...
imports: [
AgmCoreModule.forRoot({
apiKey: Example.Namespace.GoogleMapsApiKey,
})
],
// ...
})
export class AppModule {}
I thought creating a type definition for some const global variable with the value I needed would get included during the AOT build process. However, as it turns out the AOT compiler only supports a subset of TypeScript tools, which prevented the variable from getting included at compilation time. Effectively what was happening was an "Only initialized variables and constants" error without an error getting emitted from the Angular CLI. Once I made the switch to use some kind of LAZY_MAPS_API_CONFIG
provider using a class I was able to successfully .
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
Most helpful comment
Depends on what kind of build tool you are using (e.g. angular-cli or custom webpack or ...) and where the variable should come from.
This can be a little tricky. Specially when you also want to use AOT compiling, which prevents too much dynamic code inside the
@NgModule
.The solution I currently implemented is overriding the 'lazy config provider' in my main app.module.
In the module where I actually use the map, I use an empty config in the forRoot:
In my app.module.ts:
import the injection token:
Add to providers in
@NgModule
:And implement that 'GoogleMapsConfig' class, which should implement the
LazyMapsAPILoaderConfigLiteral
interface (from ' from 'angular2-google-maps/core/services').In that injectable I can inject other services and read the config from somewhere.
(e.g. if you use angular-cli you can import environments there). Or maybe read out the domain from the browser... or call an serverside API...