Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save msaxena25/fa59c2130642de3ef6330c6cff2ce6c2 to your computer and use it in GitHub Desktop.
Save msaxena25/fa59c2130642de3ef6330c6cff2ce6c2 to your computer and use it in GitHub Desktop.
AgmCoreModule - Load Google API KEY Dynamically from Angular service
#Create a CustomLazyAPIKeyLoader class file and extends MapsAPILoader
import { GoogleMapsScriptProtocol, LAZY_MAPS_API_CONFIG, LazyMapsAPILoaderConfigLiteral, MapsAPILoader } from '@agm/core';
import { DocumentRef, WindowRef } from '@agm/core/utils/browser-globals';
import { Inject, Injectable } from '@angular/core';
import { AppGlobals } from './../../Common/Services/app.global';
@Injectable()
export class CustomLazyAPIKeyLoader extends MapsAPILoader {
private _scriptLoadingPromise: Promise;
private _config: LazyMapsAPILoaderConfigLiteral;
private _windowRef: WindowRef;
private _documentRef: DocumentRef;
constructor(@Inject(LAZY_MAPS_API_CONFIG) config: any, w: WindowRef, d: DocumentRef, private appGobal: AppGlobals) {
super();
this._config = config || {};
this._windowRef = w;
this._documentRef = d;
}
load(): Promise {
if (this._scriptLoadingPromise) {
return this._scriptLoadingPromise;
}
const script = this._documentRef.getNativeDocument().createElement('script');
script.type = 'text/javascript';
script.async = true;
script.defer = true;
const callbackName: string = `angular2GoogleMapsLazyMapsAPILoader`;
// You can hit an http request to get key by http.get method.
// Here I have already loaded that key before and saved in global service file and used here...
let key = this.appGobal.googleApiKey; // GET OUR KEY FROM YourAPI.json API --
console.log('map key', key);
this._config.apiKey = key;
script.src = this._getScriptSrc(callbackName);
this._documentRef.getNativeDocument().body.appendChild(script);
this._scriptLoadingPromise = new Promise((resolve: Function, reject: Function) => {
(this._windowRef.getNativeWindow())[callbackName] = () => { console.log("loaded"); resolve(); };
script.onerror = (error: Event) => { reject(error); };
});
return this._scriptLoadingPromise;
}
private _getScriptSrc(callbackName: string): string {
let protocolType: GoogleMapsScriptProtocol =
(this._config && this._config.protocol) || GoogleMapsScriptProtocol.HTTPS;
let protocol: string;
switch (protocolType) {
case GoogleMapsScriptProtocol.AUTO:
protocol = '';
break;
case GoogleMapsScriptProtocol.HTTP:
protocol = 'http:';
break;
case GoogleMapsScriptProtocol.HTTPS:
protocol = 'https:';
break;
}
const hostAndPath: string = this._config.hostAndPath || 'maps.googleapis.com/maps/api/js';
const queryParams: { [key: string]: string | Array } = {
v: this._config.apiVersion || '3',
callback: callbackName,
key: this._config.apiKey,
client: this._config.clientId,
channel: this._config.channel,
libraries: this._config.libraries,
region: this._config.region,
language: this._config.language
};
const params: string =
Object.keys(queryParams)
.filter((k: string) => queryParams[k] != null)
.filter((k: string) => {
// remove empty arrays
return !Array.isArray(queryParams[k]) ||
(Array.isArray(queryParams[k]) && queryParams[k].length > 0);
})
.map((k: string) => {
// join arrays as comma seperated strings
let i = queryParams[k];
if (Array.isArray(i)) {
return { key: k, value: i.join(',') };
}
return { key: k, value: queryParams[k] };
})
.map((entry: { key: string, value: string }) => { return `${entry.key}=${entry.value}`; })
.join('&');
return `${protocol}//${hostAndPath}?${params}`;
}
}
#2: Add above file in app.modules.ts file :
import { CustomLazyAPIKeyLoader } from './Services/custom-apikey-loader.service';
// And Add in providers config like :
{ provide: MapsAPILoader, useClass: CustomLazyAPIKeyLoader }
@nullifiedtsk
Copy link

nullifiedtsk commented Feb 8, 2019

It can be done with much less code

import { LAZY_MAPS_API_CONFIG, LazyMapsAPILoader } from '@agm/core';
import { DocumentRef, WindowRef } from '@agm/core/utils/browser-globals';
import { Inject, Injectable } from '@angular/core';
import { AsyncMapsConfigService } from '../path/to/async/service.ts';
import { map } from 'rxjs/operators';

@Injectable()
export class CustomLazyMapsAPILoader extends LazyMapsAPILoader {
    constructor(private asyncMapsConfigService: AsyncMapsConfigService, @Inject(LAZY_MAPS_API_CONFIG) config: any, w: WindowRef, d: DocumentRef) {
        super(config, w, d);
    }

    load(): Promise<any> {
        if (this._scriptLoadingPromise) {
            return this._scriptLoadingPromise;
        }

        this.asyncMapsConfigService.settingObservable$.pipe(
            map(result => {
                this._config = { ...this._config, language: result.locale };
                return super.load();
            })
        ).toPromise();
    }
}

@SC-JC
Copy link

SC-JC commented Apr 23, 2019

@nullifiedtsk

How did you inject AsyncMapsConfigService into the loader?
I either get an error that the compilter can't resolve it or during runtime that settingObservable$ is a property of undefined.

And even if i don't use any services and just have my own BehaviourSubject as observable i get an error in super.load().

`import { LAZY_MAPS_API_CONFIG, LazyMapsAPILoader } from '@agm/core';
import { DocumentRef, WindowRef } from '@agm/core/utils/browser-globals';
import { Inject, Injectable } from '@angular/core';
import { map } from 'rxjs/operators';
import { BehaviorSubject } from 'rxjs';

export class AsyncMapsConfigService {
private setting$ = new BehaviorSubject({ apiKey: '' })
get settingObservable$() {
setTimeout(resp => this.setting$.next({ apiKey: 'myKey' }), 500)
return this.setting$.asObservable()
}
}

@Injectable()
export class CustomLazyMapsAPILoader extends LazyMapsAPILoader {
constructor(@Inject(LAZY_MAPS_API_CONFIG) config: any, w: WindowRef, d: DocumentRef, private asyncMapsConfigService: AsyncMapsConfigService) {
super(config, w, d);
this.asyncMapsConfigService = new AsyncMapsConfigService()
}

load(): Promise<any> {
    if (this._scriptLoadingPromise) {
        return this._scriptLoadingPromise;
    }

    this.asyncMapsConfigService.settingObservable$.pipe(
        map(result => {
            console.log(result)
            this._config.apiKey = result.apiKey;
            return super.load();
        })
    ).toPromise();
}

}`

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment