简体   繁体   中英

How to wait till the google maps API has loaded before loading a google.maps.OverlayView derived class

I have a separate label.js file in which I have defined a custom overlay. It uses the google.maps.OverlayView as its prototype:

Label.prototype = new google.maps.OverlayView();

I am not sure where to place the script tags for this js file in my index.html file. If I place the script tags below the google maps loading tag like so:

....
        <script async defer
            src="https://maps.googleapis.com/maps/api/js?...
        </script>
        <script src="js/label.js"></script>
    </body>
</html>

The label.js file is loaded immediately while the maps api has not yet loaded causing an error.

I currently solve this by manually loading the JS in my maps loaded callback:

function initMap() {
    gMap = new google.maps.Map(document.getElementById(strMapDivName), {
        center: {lat: 21, lng: 78},
        mapTypeId: google.maps.MapTypeId.HYBRID,
        zoom: 6,
        heading: 90,
        tilt: 0
    });

    // Load label.js afterwards so we can be sure that the google maps api has loaded
    var fileref=document.createElement('script')
    fileref.setAttribute("type","text/javascript")
    fileref.setAttribute("src", "js/label.js")

    document.getElementsByTagName("head")[0].appendChild(fileref)

}

Is this the best way to solve this?

You should include a callback function in the API call.

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

You can then include any maps related code within the callback function:

function myFunction() {
  // Your code here
}

If you need to wait until the map is "ready" ie, the map is displayed with the map options and "idle" you can use:

google.maps.event.addListenerOnce(map, 'idle', function () {
    // map is ready
});

But you should still include this within the callback function.

Here is a generic that I made and works for me.

1) Define the function you want to execute after Google maps is loaded

function ToExecuteAfterLoaded()
  {
  // Doing something here ///
  console.log("Executing this function"); // per example //
  }

2) Waiting function

function WhenGoogleLoadedDo(fnt)
   {
   if(typeof google != 'undefined')
      fnt();
   else
      setTimeout(function()
         {(function(fnt)
            {
            WhenGoogleLoadedDo(fnt)
            })(fnt)}, 500); // You can set timer as you wish //
   }

3) Call the ToExecuteAfterLoaded like this in your script

WhenGoogleLoadedDo(ToExecuteAfterLoaded);

I know it's too late, but I use this code below

var mapWaitCount = 0;
var mapWaitMax = 5;

function map_load(param1, param2, ...) { // if you need any param
    mapWaitCount++;
    // if api is loaded
    if(typeof google != 'undefined') {
        // your code here 
    }
    // try again if until maximum allowed attempt
    else if(mapWaitCount < mapWaitMax) {
        console.log('Waiting attempt #' + mapWaitCount); // just log
        setTimeout(function() { map_load(); }, 1000);
    }
    // if failed after maximum attempt, not mandatory
    else if(mapWaitCount >= mapWaitMax) {
        console.log('Failed to load google api');
    }
}

map_load(param1, param2, ...) { // if you need any param

It uses timeout to wait for the load, and after several attempts it will be stopped

What about wrapping your custom label with DOMContentLoaded?

      document.addEventListener("DOMContentLoaded", function(event) {
            Label.prototype = new google.maps.OverlayView();
      });

Reference: https://developer.mozilla.org/en-US/docs/Web/Events/DOMContentLoaded

Updating an old question; in React I used the NPM module: load-google-maps-api

I started barking down the tree of creating that myself, before realising this existed and could save some time.

It's going to load the maps API in a promise format and so you can provide a callback function for after load.

loadGoogleMapsApi().then(function (googleMaps) {
  new googleMaps.Map(document.querySelector('.map'), {
    center: {
      lat: 40.7484405,
      lng: -73.9944191
    },
    zoom: 12
  })
}).catch(function (error) {
  console.error(error)
})

Typescript way of doing

You can now use the Google Maps JavaScript API Loader library

  1. run npm i @googlemaps/js-api-loader
  2. Use the loader
const loader = new Loader({
  apiKey: "",
  version: "weekly"
});

JavaScript way

  1. Subscribe to the loader promise
loader
  .load()
  .then((google) => {
    new google.maps.Map(document.getElementById("map"), mapOptions);
  })
  .catch(e => {
    // do something
  });

Libraries way Ex: angular

  1. Subscribe to the loader promise
isMapApiLoaded?: boolean

loader
  .load()
  .then((google) => {
     this.isMapApiLoaded = true
  })
  .catch(e => {
    // do something
  });
  1. Show the map only when loaded
<google-map *ngIf="isMapApiLoaded"> 
  <!-- ... -->
</google-map>

Additional (singleton)

  1. You could use the loader in a service that you then import globally
export class MapLoaderService {
  onMapApiDidLoad$: BehaviorSubject<boolean> = new BehaviorSubject(null)
  
  private _initLoader() {
    this.mapLoader
      .load()
      .then((google) => {
        this.onMapApiDidLoad$.next(true)
      })
      .catch((e) => {
        this.onMapApiDidLoad$.next(false)
      })
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM