AngularJS + Leaflet - 初始化服务上的传单地图

时间:2015-11-30 12:55:12

标签: angularjs leaflet angular-leaflet-directive

我正在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参数,但我仍然无法使其工作 - 尽管我有可能没有传递应该的内容。

1 个答案:

答案 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: '&copy; <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