route google angularjs google-maps lazy-loading directive

route - AngularJS: carga el script de google map de forma asíncrona en la directiva para múltiples mapas



ng map route (1)

Actualmente estoy tratando de cargar varios mapas de Google en una sola página. No quiero incluir el script API de google map en el código HTML, ya que no quiero que se cargue el script a menos que los mapas estén en la página actual. Quiero que se llame a mis mapas dentro de una sola directiva que también realizará la carga perezosa del script API de google map.

Así que busqué y encontré una solución que modifiqué un poco, pero mi problema es que solo cargará un mapa pero no los otros.

Mi HTML se ve así:

<div id="mapParis" class="google-map" lat="48.833" long="2.333"></div> <div id="mapWashington" class="google-map" lat="38.917" long="-77.000"></div> <div id="mapTokyo" class="google-map" lat="35.667" long="139.750"></div>

Y la directiva:

// Google Map app.directive(''googleMap'', [''$window'', ''$q'', function( $window, $q ) { function loadScript() { console.log(''loadScript''); // use global document since Angular''s $document is weak var s = document.createElement(''script''); s.src = ''//maps.googleapis.com/maps/api/js?sensor=false&language=en&callback=initMap''; document.body.appendChild(s); } // Lazy loading of the script function lazyLoadApi(key) { console.log(''lazyLoadApi''); var deferred = $q.defer(); $window.initMap = function () { deferred.resolve(); }; if ( $window.attachEvent ) { $window.attachEvent(''onload'', loadScript); } else { $window.addEventListener(''load'', loadScript, false); } return deferred.promise; } return { restrict: ''C'', // restrict by class name scope: { mapId: ''@id'', // map ID lat: ''@'', // latitude long: ''@'' // longitude }, link: function($scope, elem, attrs) { // Check if latitude and longitude are specified if ( angular.isDefined($scope.lat) && angular.isDefined($scope.long) ) { console.log(''-----''); // Initialize the map $scope.initialize = function() { console.log($scope.mapId); $scope.location = new google.maps.LatLng($scope.lat, $scope.long); $scope.mapOptions = { zoom: 6, center: $scope.location }; $scope.map = new google.maps.Map(document.getElementById($scope.mapId), $scope.mapOptions); new google.maps.Marker({ position: $scope.location, map: $scope.map, }); } // Check if google map API is ready to run if ( $window.google && $window.google.maps ) { console.log(''gmaps already loaded''); // Google map already loaded $scope.initialize(); } else { lazyLoadApi().then(function () { // Promised resolved console.log(''promise resolved''); if ( $window.google && $window.google.maps ) { // Google map loaded console.log(''gmaps loaded''); $scope.initialize(); } else { // Google map NOT loaded console.log(''gmaps not loaded''); } }, function () { // Promise rejected console.log(''promise rejected''); }); } } } };

Aquí hay un jsFiddle con 3 mapas, verás que solo se carga el último:
http://jsfiddle.net/5Pk8f/1/

Supongo que estoy haciendo algo mal con mi alcance o con la forma en que se maneja la promesa, pero por ahora no tengo ideas ...

¡Gracias! (y lo siento por mi no tan buen inglés)

Actualizar (después de la respuesta)

Como actualización, aquí está la solución completa que se me ocurrió:
http://plnkr.co/edit/1NpquJ?p=preview (@maurycy plunker)

Servicio de mapas de Google

// Lazy loading of Google Map API app.service(''loadGoogleMapAPI'', [''$window'', ''$q'', function ( $window, $q ) { var deferred = $q.defer(); // Load Google map API script function loadScript() { // Use global document since Angular''s $document is weak var script = document.createElement(''script''); script.src = ''//maps.googleapis.com/maps/api/js?sensor=false&language=en&callback=initMap''; document.body.appendChild(script); } // Script loaded callback, send resolve $window.initMap = function () { deferred.resolve(); } loadScript(); return deferred.promise; }]);

Directiva de mapas de Google

// Google Map app.directive(''googleMap'', [''$rootScope'', ''loadGoogleMapAPI'', function( $rootScope, loadGoogleMapAPI ) { return { restrict: ''C'', // restrict by class name scope: { mapId: ''@id'', // map ID lat: ''@'', // latitude long: ''@'' // longitude }, link: function( $scope, elem, attrs ) { // Check if latitude and longitude are specified if ( angular.isDefined($scope.lat) && angular.isDefined($scope.long) ) { // Initialize the map $scope.initialize = function() { $scope.location = new google.maps.LatLng($scope.lat, $scope.long); $scope.mapOptions = { zoom: 12, center: $scope.location }; $scope.map = new google.maps.Map(document.getElementById($scope.mapId), $scope.mapOptions); new google.maps.Marker({ position: $scope.location, map: $scope.map, }); } // Loads google map script loadGoogleMapAPI.then(function () { // Promised resolved $scope.initialize(); }, function () { // Promise rejected }); } } }; }]);

Muestra de uso de HTML

<div id="mapParis" class="google-map" lat="48.833" long="2.333"></div> <div id="mapWashington" class="google-map" lat="38.917" long="-77.000"></div> <div id="mapTokyo" class="google-map" lat="35.667" long="139.750"></div>

Gracias de nuevo a maurycy


Tiene un problema aquí con promesas e inicialización, lo he hecho más limpio para usted.

Al parecer, el jsfiddle se ha eliminado, por lo que aquí está trabajando plunker: http://plnkr.co/edit/1NpquJ?p=preview

js

Aquí hay un servicio para gmaps de carga perezosa.

app.service(''lazyLoadApi'', function lazyLoadApi($window, $q) { function loadScript() { console.log(''loadScript'') // use global document since Angular''s $document is weak var s = document.createElement(''script'') s.src = ''//maps.googleapis.com/maps/api/js?sensor=false&language=en&callback=initMap'' document.body.appendChild(s) } var deferred = $q.defer() $window.initMap = function () { deferred.resolve() } if ($window.attachEvent) { $window.attachEvent(''onload'', loadScript) } else { $window.addEventListener(''load'', loadScript, false) } return deferred.promise });

entonces la directiva hace lo que debería hacer, trabajar solo con map, no cargar archivos js en ninguna otra lógica