Load Google Maps API with AJAX... but only once for multiple instances

ajax, google-maps, javascript, jquery, json

Solution

There are two separate issues that can occur here.

- Because you are calling the googleMaps() function each time, you are creating a new instance of the object which tracks when/if the google maps api has loaded. You need to extract the part that loads the api outside of the googleMaps function (or use a shared variable).

- Even if you kept the loadAPI function as is you can still encounter a race condition where the ajax request to load the google maps library can be fired off twice. The reason why you are seeing that error is that when you check in loadAPI if the google object is available, it hasn't actually been set up yet by the first ajax request.

You can use the Promise API to deal with issues like this. I changed the loadAPI method to use a promise, and like I said, it needs to be moved outside of the googleMaps function

        var loadAPIPromise;
        // Load API
        function loadAPI(callback) {
            if (!loadAPIPromise) {
                var deferred = $.Deferred();
                $.ajax({
                    url: 'http://www.google.com/jsapi/',
                    dataType: "script",
                    success: function() {
                        google.load('maps', '3', {
                            callback: function() {
                                deferred.resolve();
                            }, 
                            other_params: 'sensor=false'
                        });
                    }
                });
                loadAPIPromise = deferred.promise();
            }
            loadAPIPromise.done(callback);
        };

Here is a jsfiddle example http://jsfiddle.net/callado4/gA79R/4/

Problem

I wrote a little script, which loads Google Maps markers from a JSON file and puts them on a map. The script should be able to handle multiple instances. At the moment the script looks like this (for testing i used this JSON file): ``` <div id="map" data-file="test.json" style="width: 200px; height: 200px; "></div> <div id="map2" data-file="test2.json" style="width: 200px; height: 200px; "></div> <!-- JAVASCRIPT --> <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script> <script> $(function() { var googleMaps = function() { var $el, apiLoaded = false; // Init // @public function init(el) { $el = $(el); loadData($el.data('file')); }; // Creating a marker and putting it on the map // @private function createMarker(data) { var marker = new google.maps.Marker({ position: new google.maps.LatLng(data.lat, data.lng), map: map, title: data.title }); } // JSON file and API loaded // @private function ready(data) { // Basic settings var mapOptions = { center: new google.maps.LatLng(58, 16), zoom: 7, mapTypeId: google.maps.MapTypeId.ROADMAP }; map = new google.maps.Map($el[0], mapOptions); // Create markers $.each(data, function(key, value) { createMarker(value); }); } // Load API // @private function loadAPI(callback) { if (typeof google === 'object' && typeof google.maps === 'object') { // API was already loaded if(typeof(callback) === 'function') { callback(); } } else { // API wasn't loaded yet // Send an AJAX request $.ajax({ url: 'http://www.google.com/jsapi/', dataType: "script", success: function() { google.load('maps', '3', { callback: function() { // Check if callback function is set if(typeof(callback) === 'function') { callback(); } }, other_params: 'sensor=false' }); } }); } }; // Load JSON file // @private function loadData(file) { $.ajax({ url: file, success: function(data) { var parsedJson = $.parseJSON(data); loadAPI(function() { ready(parsedJson); }); }, error: function(request, status, error) { // Error console.log(error); } }); }; return { init: init } } }); </script> ``` It works if i only `.init()` one instance like so: ``` googleMaps().init(document.getElementById('map')); ``` But it fails as soon as i try multiple instances: ``` googleMaps().init(document.getElementById('map')); googleMaps().init(document.getElementById('map2')); ``` I think it fails because the `.loadAPI()` and `google.load()` function are getting called twice in a row and my check inside `.loadAPI()` if the Google Maps API was already loaded fails (Chrome Inspector: Uncaught TypeError: Object # has no method 'Load' (Google Maps API JS file) ). How do i make sure that my AJAX request inside the `.loadAPI()` function doesn't get called twice? I could use a global variable outside my Module Pattern, which i set to true, but i don't really want to use one for that purpose. Is there anything other i could use? Thanks in advance.

Original source

Related problems