Reputation: 162
I am building an app that lets you edit maps, the editor has google maps with the Agm map module, the end result for the user is an iframe with his map to embed into his webpage. I am using the module for the editor, and in the app.module.ts I import it with my API key.
import { AgmCoreModule } from '@agm/core';
...
imports: [
...
AgmCoreModule.forRoot({
apiKey: 'YOUR_KEY'
})
]
The iframe will be a separate angular app that uses the same back-end. I would need the user's API key that will be fetched from the database but I can't get my head around on how can I build this part in Angular, it seems it creates the build with the api key, is it possible to do it in a way the key is modified on runtime? I've seen it done in jQuery. Where it can be fetched from the code in the script tag, or in vanilla js, an example:
<script async defer
src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap">
</script>
In this last example it can be easily done, Thank you
Upvotes: 2
Views: 5040
Reputation: 11
AppModule.ts file
import {APP_INITIALIZER} from '@angular/core';
import { LAZY_MAPS_API_CONFIG, LazyMapsAPILoaderConfigLiteral } from '@agm/core';
import { GoogleMapsInitializer } from './shared/services/googleMapsInitializer';
imports: [
AgmCoreModule.forRoot({
apiKey: '',// this should be empty
libraries: ['places']
})
],
providers: [
{
// APP_INITIALIZER is the Angular dependency injection token.
provide: APP_INITIALIZER,
// Pass in the AGM dependency injection token.
deps: [LAZY_MAPS_API_CONFIG, GoogleMapsInitializer],
// Allow for multiple startup injectors if needed.
multi: true,
// UseFactory provides Angular with the function to invoke.
useFactory: (config: LazyMapsAPILoaderConfigLiteral, initializer: GoogleMapsInitializer) => () => initializer.initialize(config),
}]
GoogleMapsInitializer service
import { LazyMapsAPILoaderConfigLiteral } from '@agm/core';
import { GoogleMapsConfigService } from '../rest-services/googleMapsConfigService';
export class GoogleMapsInitializer {
constructor(private googleMapsConfigService: GoogleMapsConfigService) { }
async initialize(config: LazyMapsAPILoaderConfigLiteral): Promise<void> {
try {
const apiKey = await this.googleMapsConfigService.getGoogleMapsApiKey();
console.log("API KEY IN INITIALIZE SERVICE ==> ", apiKey)
config.apiKey = apiKey;
} catch (error) {
console.error('Error setting Google Maps API key:', error);
}
}
}
GoogleMapsConfigService service
import { HttpClient } from '@angular/common/http';
export class GoogleMapsConfigService {
constructor(private http: HttpClient) {}
getGoogleMapsApiKey(): Promise<string> {
const API_KEY_ENDPOINT = 'your api goes here';// get api key of google maps from backend service
return this.http.post<any>(API_KEY_ENDPOINT, {}).toPromise()
.then(response => response.apikey as string) // Replace 'apiKey' with the actual property name returned by your backend API.
.catch(error => {
console.error('Error fetching Google Maps API key:', error);
return '';
});
}
}
During app startup, the APP_INITIALIZER in AppModule triggers the GoogleMapsInitializer service. The GoogleMapsInitializer service fetches the Google Maps API key using GoogleMapsConfigService. Once the key is obtained, it is dynamically set in the config object for AgmCoreModule.
Upvotes: 1
Reputation: 197
Adding to above answer, add the below to make the auto complete work
AgmCoreModule.forRoot({
apiKey: 'initialKey',
language: 'en',
libraries: ['places']
}),
Upvotes: 1
Reputation: 162
I did solve it straight away, in my case I got the key from the API with this code
import { AgmCoreModule, LAZY_MAPS_API_CONFIG, LazyMapsAPILoaderConfigLiteral }
from '@agm/core';
export function agmConfigFactory(http: HttpClient, config: LazyMapsAPILoaderConfigLiteral) {
const id = window.location.pathname.replace(/\//g, "");
return () => http.get<any>(`${environment.baseUrl}/map-display/${id}`).pipe(
map(response => {
config.apiKey = response.key;
return response;
})
).toPromise();
}
The content of the api call and the id can be substituted with the desired key.
import { AgmCoreModule, LAZY_MAPS_API_CONFIG, LazyMapsAPILoaderConfigLiteral }
from '@agm/core';
@Injectable()
export class GoogleMapsConfig implements LazyMapsAPILoaderConfigLiteral {
apiKey: string = CONFIG.googleMapsAPIKey;
}
you must add a provider specifying the function to the providers array in @NgModule, in my case:
providers: [
{
provide: APP_INITIALIZER,
useFactory: agmConfigFactory,
deps: [HttpClient, LAZY_MAPS_API_CONFIG],
multi: true
}
],
You can useClass instead of useFactory for the generic example I showed. You still have to provide an initial key in the imports array of @NgModule, it can be a meaningless string
AgmCoreModule.forRoot({ apiKey: "initialKey"}),
Upvotes: 2