我正在AngularJS中构建一个应用程序,它使用LeafletJS与地图进行交互,提供在我称之为阶段的不同可能的交互。对于每个阶段,都有UIRouter
状态及其控制器和模板。
我目前正在通过服务提供传单功能。想法是该服务初始化Leaflet地图并提供对该州控制器的一些有限访问。因此,这些控制器会调用setupMarkersInteractions
等服务功能来设置回调,以便在地图上放置标记。
但是,我在通过Leaflet的leaflet.map()
函数初始化地图时遇到了问题,即:Error: Map container not found
。这与Leaflet无法找到与地图相关联的HTML元素有关。
目前,我有点这样做:
function mapService() {
var map;
return {
initializeMap : initializeMap,
setupMarkersInteractions : setupMarkersInteractions
};
function initializeMap() {
map = leaflet.map('map');
}
function setupMarkersInteractions() {
map.on('click', markerPlacementCallback);
}
}
initializeMap
函数告诉leaflet.map
查找带有id='map'
的HTML元素,该元素在州的模板上声明。
现在,对于实际问题,这是否与某种 AngularJS服务无法访问HTML模板有关?我在这个问题上找不到任何内容,但我认为服务不能直接访问视图是有意义的...
如果是,我应该探索什么样的解决方法?我查看了leaflet-directive
,但它似乎没有提供添加和删除自定义回调的可能性,我希望具有灵活性(当我使用Leaflet-Freedraw添加免费绘制功能时,事情会变得复杂,因为例子)。
我考虑直接使用leaflet.map
为元素的HTMLElement
参数,但我仍然无法使其工作 - 尽管我有可能没有传递应该的内容。
答案 0 :(得分:5)
发生的事情是L.Map
尝试从您的服务访问DOM时,该模板尚可用。通常,服务被加载并注入控制器,控制器初始化其范围,之后模板被初始化并添加到DOM。你会看到你是否会在你的地图初始化上放置一个大的超时,它会找到它的DOM元素。但那是一个非常丑陋的黑客攻击。在Angular中,您应该使用指令向DOM元素添加逻辑。
例如,模板:<leaflet></leaflet>
及其非常基本的指令:
angular.module('app').directive('leaflet', [
function () {
return {
replace: true,
template: '<div></div>',
link: function (scope, element, attributes) {
L.map(element[0]);
}
};
}
]);
您可以将其连接到您的服务并将该元素传递给初始化方法:
angular.module('app').directive('leaflet', [
'mapService'
function (mapService) {
return {
replace: true,
template: '<div></div>',
link: function (scope, element, attributes) {
mapService.initializeMap(element[0]);
}
};
}
]);
这样,只有在实际DOM元素可用时才会调用initializeMap
方法。但它给你带来了另一个问题。在您的控制器初始化时,您的服务尚未准备就绪。您可以使用承诺解决此问题:
angular.module('app').factory('leaflet', [
'$q',
function ($q) {
var deferred = $q.defer();
return {
map: deferred.promise,
resolve: function (element) {
deferred.resolve(new L.Map(element));
}
}
}
]);
angular.module('app').directive('leaflet', [
'leaflet',
function (leaflet) {
return {
replace: true,
template: '<div></div>',
link: function (scope, element, attributes) {
leaflet.resolve(element[0]);
}
};
}
]);
如果您想在控制器中使用地图实例,现在可以等到它已经解决:
angular.module('app').controller('rootController', [
'$scope', 'leaflet',
function ($scope, leaflet) {
leaflet.map.then(function (map) {
var tileLayer = L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>',
maxZoom: 18
}).addTo(map);
map.setView([0, 0], 1);
L.marker([0, 0]).addTo(map);
});
}
]);
以下是关于Plunker的概念示例:http://plnkr.co/edit/DoJpGqtR7TWmKAeBZiYJ?p=preview