AngularJS - 在多个地图的指令中异步加载谷歌地图脚本 [英] AngularJS - load google map script async in directive for multiple maps
问题描述
我目前正在尝试在单个页面上加载多个谷歌地图.我不想在 HTML 代码中包含 google map API 脚本,因为我不希望加载脚本,除非地图在当前页面中.我希望在单个指令中调用我的地图,该指令还将执行 google map API 脚本延迟加载.
I am currently trying to load multiple google maps on a single page. I don't want to include google map API script into the HTML code as I don't want the script to be loaded unless the maps are in the current page. I want my maps to be called inside a single directive that will also perform the google map API script lazy loading.
所以我四处搜索并找到了一个解决方案,我稍微调整了一下,但我的问题是它只会加载一张地图,而不会加载其他地图.
So I searched around and found a solution that I tweaked a bit, but my problem is that it will only load one map but not the others.
我的 HTML 如下所示:
My HTML looks like this:
<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>
还有指令:
// 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');
});
}
}
}
};
这是一个带有 3 张地图的 jsFiddle,你会看到只有最后一张被加载:
http://jsfiddle.net/5Pk8f/1/
Here is a jsFiddle with 3 maps, you will see that only the last one is loaded:
http://jsfiddle.net/5Pk8f/1/
我想我的范围或处理承诺的方式有问题,但我现在完全没有想法......
I guess that I am doing something wrong with my scope or the way the promise is handled, but I am quite out of ideas for now...
谢谢!(抱歉我的英语不太好)
作为更新,这是我想出的完整解决方案:
http://plnkr.co/edit/1NpquJ?p=preview (@maurycyplunker)
As an update,
here the the full solution I came up with:
http://plnkr.co/edit/1NpquJ?p=preview (@maurycy plunker)
// 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;
}]);
谷歌地图指令
// 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
});
}
}
};
}]);
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>
再次感谢 maurycy
Thanks again to maurycy
推荐答案
你在 promise 和初始化方面有问题,我已经为你简化了
you have a problem here with promises and initialisation, i've made it cleaner for you
显然 jsfiddle 已被删除,所以这里是工作 plunker:http://plnkr.co/编辑/1NpquJ?p=预览
Apparently the jsfiddle has been removed so here is working plunker: http://plnkr.co/edit/1NpquJ?p=preview
这里是延迟加载 gmaps 的服务
here is a service for lazy load gmaps
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
});
然后指令做它应该做的事情,只使用地图,不要在任何其他逻辑上加载 js 文件
then the directive does what it should do, work only with map, don't load js files on any other logic
这篇关于AngularJS - 在多个地图的指令中异步加载谷歌地图脚本的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!