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