Habituellement, dans un site JavaScript simple, je peux utiliser le script suivant pour référencer Google Maps api et définir la fonction callback
avec initMap
.
<script async defer src="https://maps.googleapis.com/maps/api/js?callback=initMap"></script>
Ce que j’ai observé, c’est que la fonction initMap
du site JavaScript simple se trouve dans la portée de la fenêtre. Elle peut être référencée dans les paramètres de script - ?callback=initMap
, mais une fois que j’écris un composant dans angular2 avec une méthode de composant appelée initMap
, la variable initMap
sera dans le cadre de mon composant. Ensuite, le script de chargement asynchrone que j'ai configuré dans l'index ne pourra pas intercepter ma méthode de composant initMap
.
Angular2
?PS: Je sais qu'un composant
angular2-google-maps
est disponible dansalpha
vianpm
, mais il est actuellement livré avec des fonctionnalités limitées. Je voudrais donc savoir comment le charger de manière plus simple sans utiliser un autre composant afin que je puisse simplement utiliser Google Maps. api pour mettre en œuvre mon projet.
Je vois que vous ne voulez pas d'autre composant, mais le polymère a des composants qui fonctionnent bien avec Google Apis. J'ai angular2 code qui utilise le polymère youtube data api. J'ai eu de l'aide pour le configurer. Voici le plunker qui m’a lancé. Je pense que la partie dure se prépare pour ce rappel, je suis sûr que vous pouvez le faire sans polymère. L'exemple montre la partie délicate qu'un service angulaire est utilisé pour tout brancher.
const url = 'https://apis.google.com/js/client.js?onload=__onGoogleLoaded'
export class GoogleAPI {
loadAPI: Promise<any>
constructor(){
this.loadAPI = new Promise((resolve) => {
window['__onGoogleLoaded'] = (ev) => {
console.log('gapi loaded')
resolve(window.gapi);
}
this.loadScript()
});
}
doSomethingGoogley(){
return this.loadAPI.then((gapi) => {
console.log(gapi);
});
}
loadScript(){
console.log('loading..')
let node = document.createElement('script');
node.src = url;
node.type = 'text/javascript';
document.getElementsByTagName('head')[0].appendChild(node);
}
}
Je suis tombé sur cette idée en essayant de développer une application Web progressive, c’est-à-dire où il était possible de ne pas être en ligne. Il y avait une erreur dans les exemples de code: onload
dans le script google maps devrait être callback
. Donc, ma modification de user2467174 a conduit à
map-loader.service.ts
const url = 'http://maps.googleapis.com/maps/api/js?key=xxxxx&callback=__onGoogleLoaded';
@Injectable()
export class GoogleMapsLoader {
private static promise;
public static load() {
// First time 'load' is called?
if (!GoogleMapsLoader.promise) {
// Make promise to load
GoogleMapsLoader.promise = new Promise( resolve => {
// Set callback for when google maps is loaded.
window['__onGoogleLoaded'] = (ev) => {
resolve('google maps api loaded');
};
let node = document.createElement('script');
node.src = url;
node.type = 'text/javascript';
document.getElementsByTagName('head')[0].appendChild(node);
});
}
// Always return promise. When 'load' is called many times, the promise is already resolved.
return GoogleMapsLoader.promise;
}
}
Et puis j'ai un composant avec
import { GoogleMapsLoader } from './map/map-loader.service';
constructor() {
GoogleMapsLoader.load()
.then(res => {
console.log('GoogleMapsLoader.load.then', res);
this.mapReady = true;
})
Et un template
<app-map *ngIf='mapReady'></app-map>
De cette façon, le div de la carte n'est placé dans le dom que s'il est en ligne.
Ensuite, dans le fichier map.component.ts , nous pouvons attendre que le composant soit placé dans le DOM avant de charger la carte elle-même.
ngOnInit() {
if (typeof google !== 'undefined') {
console.log('MapComponent.ngOnInit');
this.loadMap();
}
}
Juste au cas où vous voudriez en faire une fonction statique, qui retourne toujours une promesse, mais n'obtient qu'une fois l'API.
const url = 'https://maps.googleapis.com/maps/api/js?callback=__onGoogleMapsLoaded&ey=YOUR_API_KEY';
export class GoogleMapsLoader {
private static promise;
public static load() {
// First time 'load' is called?
if (!GoogleMapsLoader.promise) {
// Make promise to load
GoogleMapsLoader.promise = new Promise((resolve) => {
// Set callback for when google maps is loaded.
window['__onGoogleMapsLoaded'] = (ev) => {
console.log('google maps api loaded');
resolve(window['google']['maps']);
};
// Add script tag to load google maps, which then triggers the callback, which resolves the promise with windows.google.maps.
console.log('loading..');
let node = document.createElement('script');
node.src = url;
node.type = 'text/javascript';
document.getElementsByTagName('head')[0].appendChild(node);
});
}
// Always return promise. When 'load' is called many times, the promise is already resolved.
return GoogleMapsLoader.promise;
}
}
Voici comment obtenir l’API dans d’autres scripts:
GoogleMapsLoader.load()
.then((_mapsApi) => {
debugger;
this.geocoder = new _mapsApi.Geocoder();
this.geocoderStatus = _mapsApi.GeocoderStatus;
});
C'est ce que j'utilise actuellement:
loadMapsScript(): Promise<void> {
return new Promise(resolve => {
if (document.querySelectorAll(`[src="${mapsScriptUrl}"]`).length) {
resolve();
} else {
document.body.appendChild(Object.assign(document.createElement('script'), {
type: 'text/javascript',
src: mapsScriptUrl,
onload: doMapInitLogic();
}));
}
});
}
Voir mes instructions plus complètes ici