22
\$\begingroup\$

Here is a simple reusable AngularJS factory I came up with to initialize Google Maps Asynchronously, which somehow does not seem to be supported by major libraries (see below):

Following Google's guidelines I am using global callback function (which seems to be unavoidable harm), that resolves a dummy promise, which is the only API returned.

Then maps can be loaded anywhere by simply calling

Initializer.mapsInitialized.
    .then(function(){
        map = new google.maps.Map(element, options);
    });

Below is the code. Any critics, potential flaws, drawbacks, violation of best practices is welcome!

// Google async initializer needs global function, so we use $window
angular.module('GoogleMapsInitializer')
    .factory('Initializer', function($window, $q){

        // maps loader deferred object
        var mapsDefer = $q.defer();

        // Google's url for async maps initialization accepting callback function
        var asyncUrl = 'https://maps.googleapis.com/maps/api/js?callback=';

        // async loader
        var asyncLoad = function(asyncUrl, callbackName) {
          var script = document.createElement('script');
          //script.type = 'text/javascript';
          script.src = asyncUrl + callbackName;
          document.body.appendChild(script);
        };

        // callback function - resolving promise after maps successfully loaded
        $window.googleMapsInitialized = function () {
            mapsDefer.resolve();
        };

        // loading google maps
        asyncLoad(asyncUrl, 'googleMapsInitialized');

        return {

            // usage: Initializer.mapsInitialized.then(callback)
            mapsInitialized : mapsDefer.promise
        };
    })

Most major libraries built for Google Maps seem to use the standard script tag

<script src='//maps.googleapis.com/maps/api/js'></script>

which is, however, blocking, may result in delays, and makes the page unsuitable for offline testing.

On another note, library such as script.js async loader, does not seem to work with this particular script.

\$\endgroup\$
0

1 Answer 1

13
\$\begingroup\$

I like it,

you could clean up the commented out code and possibly replace

    $window.googleMapsInitialized = function () {
        mapsDefer.resolve();
    };

with

    $window.googleMapsInitialized = mapsDefer.resolve;

Personally, I would re-arrange the code a tiny bit, keep the URL completely on top, keep asyncLoad and the call closer together. Keep the declaration of mapsDefer and the resolving function closer.

// Google async initializer needs global function, so we use $window
angular.module('GoogleMapsInitializer')
.factory('Initializer', function($window, $q){

    //Google's url for async maps initialization accepting callback function
    var asyncUrl = 'https://maps.googleapis.com/maps/api/js?callback=',
        mapsDefer = $q.defer();

    //Callback function - resolving promise after maps successfully loaded
    $window.googleMapsInitialized = mapsDefer.resolve; // removed ()

    //Async loader
    var asyncLoad = function(asyncUrl, callbackName) {
      var script = document.createElement('script');
      //script.type = 'text/javascript';
      script.src = asyncUrl + callbackName;
      document.body.appendChild(script);
    };
    //Start loading google maps
    asyncLoad(asyncUrl, 'googleMapsInitialized');

    //Usage: Initializer.mapsInitialized.then(callback)
    return {
        mapsInitialized : mapsDefer.promise
    };
})
\$\endgroup\$
0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.