如何在Angular2中异步加载google maps api

时间:2016-01-21 18:41:13

标签: google-maps angular

通常在普通的javascript网站中,我可以使用以下脚本来引用google maps api,并将callback函数设置为initMap

<script async defer src="https://maps.googleapis.com/maps/api/js?callback=initMap"></script>

我观察到普通javascript网站中的initMap函数位于窗口范围内,并且可以在脚本参数设置中引用 - ?callback=initMap,但是一旦我在angular2中编写了一个组件使用名为initMap的组件方法,initMap将在我的组件范围内。然后我在索引中设置的异步加载脚本将无法捕获我的组件initMap方法。

具体来说,我想知道如何在Angular2中实现同样的目标?

  

PS:我知道angular2-google-maps通过alpha提供了npm个组件,但目前它的功能有限,所以我想知道如何加载它以更简单的方式不使用其他组件,所以我可以使用谷歌地图api来实现我的项目。

4 个答案:

答案 0 :(得分:19)

我看到你不想要另一个组件,但聚合物的组件可以与谷歌apis一起使用。我有使用聚合物youtube数据api的angular2代码。我有帮助设置它。这是让我入门的plunker。我认为hardpart正在设置回调,我相信你可以在没有聚合物的情况下做到这一点。该示例显示了一个棘手的部分,角度服务用于挂钩所有内容。

    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);
        
      }
    }

答案 1 :(得分:8)

我在尝试开发渐进式网络应用程序时遇到了这个问题,即有可能无法上网。代码示例中存在错误:Google地图脚本中的onload应为callback。所以我对user2467174的修改导致了

<强>地图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;
    }
}

然后我有组件

import { GoogleMapsLoader } from './map/map-loader.service';
constructor() {

    GoogleMapsLoader.load()
    .then(res => {
        console.log('GoogleMapsLoader.load.then', res);
        this.mapReady = true;
    })

模板

<app-map *ngIf='mapReady'></app-map>

这样地图div只会在网上放入dom。

然后在 map.component.ts 中,我们可以等到组件放入DOM之后再加载地图本身。

ngOnInit() {
    if (typeof google !== 'undefined') {
        console.log('MapComponent.ngOnInit');
        this.loadMap();
    }
}

答案 2 :(得分:5)

万一你想使它成为一个静态函数,它总是返回一个promise,但只获得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;
}

}

这是你可以在其他脚本中获取api的方法:

GoogleMapsLoader.load()
            .then((_mapsApi) => {
                debugger;
                this.geocoder       = new _mapsApi.Geocoder();
                this.geocoderStatus = _mapsApi.GeocoderStatus;
            });

答案 3 :(得分:1)

这就是我目前正在使用的内容:

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();
      }));
    }
  });
}

请参阅我更全面的说明here