AngularJS
Google Maps
Asynchronous Loading
JavaScript
Web Development

How to asynchronously load a google map in AngularJS?

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

In AngularJS, Google Maps should be loaded asynchronously through one shared script loader instead of with ad hoc script tags in multiple controllers. That approach avoids race conditions, prevents duplicate script injection, and gives every map consumer the same promise-based readiness contract.

Why Direct Script Usage Breaks

AngularJS controllers and directives can run before the Google Maps script finishes downloading. If a component tries to call google.maps.Map too early, the app fails with google is undefined or similar startup-time errors that appear only under slower network conditions.

A reliable integration needs three guarantees:

  • the script is injected only once
  • all map consumers wait for one shared promise
  • failures are surfaced explicitly

Without those guarantees, one route may work while another fails depending on timing rather than code correctness.

Create a One-Time Loader Service

The usual AngularJS pattern is a service or factory that injects the script, stores one deferred object, and resolves it from the Google callback.

javascript
1angular.module("app", [])
2  .factory("mapsLoader", function($q, $window, $document) {
3    var deferred;
4
5    return function load(apiKey) {
6      if (deferred) {
7        return deferred.promise;
8      }
9
10      deferred = $q.defer();
11
12      $window.__mapsReady = function() {
13        deferred.resolve($window.google.maps);
14        delete $window.__mapsReady;
15      };
16
17      var script = $document[0].createElement("script");
18      script.src =
19        "https://maps.googleapis.com/maps/api/js?key=" +
20        apiKey +
21        "&callback=__mapsReady";
22      script.async = true;
23      script.defer = true;
24      script.onerror = function() {
25        deferred.reject(new Error("Google Maps failed to load"));
26      };
27
28      $document[0].body.appendChild(script);
29      return deferred.promise;
30    };
31  });

This gives every controller and directive the same answer to the question "is Maps ready yet."

Initialize the Map Only After the Promise Resolves

Once the service exists, map creation becomes ordinary AngularJS code that simply waits for the loader.

javascript
1angular.module("app")
2  .controller("MapCtrl", function($scope, mapsLoader) {
3    $scope.error = null;
4
5    mapsLoader("YOUR_API_KEY")
6      .then(function(maps) {
7        var center = { lat: 43.6532, lng: -79.3832 };
8
9        var map = new maps.Map(document.getElementById("map"), {
10          center: center,
11          zoom: 12
12        });
13
14        new maps.Marker({
15          position: center,
16          map: map,
17          title: "Toronto"
18        });
19      })
20      .catch(function(err) {
21        $scope.$applyAsync(function() {
22          $scope.error = err.message;
23        });
24      });
25  });

The important detail is sequencing. Map setup happens only after the external API is actually ready.

Prefer a Directive for Reusable Map Widgets

If several pages use maps, move the rendering logic into a directive so controllers stay focused on data rather than DOM setup.

javascript
1angular.module("app")
2  .directive("googleMap", function(mapsLoader) {
3    return {
4      restrict: "E",
5      scope: {
6        lat: "@",
7        lng: "@",
8        zoom: "@"
9      },
10      template: '<div style="height:320px"></div>',
11      link: function(scope, element) {
12        mapsLoader("YOUR_API_KEY").then(function(maps) {
13          var center = {
14            lat: parseFloat(scope.lat),
15            lng: parseFloat(scope.lng)
16          };
17
18          var map = new maps.Map(element.children()[0], {
19            center: center,
20            zoom: parseInt(scope.zoom || "10", 10)
21          });
22
23          scope.$on("$destroy", function() {
24            maps.event.clearInstanceListeners(map);
25          });
26        });
27      }
28    };
29  });

This keeps script ownership centralized while making the actual map widget reusable.

Handle Failures and Operations Explicitly

Asynchronous loading means asynchronous failure. Blank map containers are not enough. Treat map loading like any other external dependency and make failure visible.

At minimum, handle:

  • script download failure
  • invalid or restricted API keys
  • quota exhaustion
  • pages that mount and unmount maps repeatedly

If the app is a long-lived single-page dashboard, clean up listeners on scope destruction so route changes do not accumulate stale map objects and callbacks over time.

Common Pitfalls

The most common mistake is injecting the Google Maps script from multiple controllers or directives. That creates duplicate global callbacks and unpredictable load order.

Another common issue is initializing the map before the loader promise resolves, which works on fast connections and fails elsewhere. Developers also often forget to surface API-key and quota failures, so users see an empty map area with no meaningful error path.

Summary

  • Load Google Maps through one shared AngularJS service, not with repeated script tags.
  • Return a shared promise so every consumer waits for the same readiness signal.
  • Create maps only after the loader promise resolves.
  • Use directives for reusable map widgets and clean up listeners on destroy.
  • Treat network, key, and quota failures as explicit application states instead of silent frontend glitches.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.