javascriptangulargoogle-mapsagmagm-map

Change agm-map google maps API Key dynamically in Angular 7


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


Solution

  • 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"}),