1

我正在 AngularJS 中构建一个应用程序,该应用程序使用 LeafletJS 与地图进行交互,提供不同的可能交互,这些交互在我所说的阶段之间分离。对于这些阶段中的每一个,都有一个UIRouter状态,带有它的控制器和模板。

我目前正在通过服务提供传单功能。这个想法是让该服务初始化一个传单地图并提供对状态控制器的一些有限访问。例如,这些控制器将调用服务函数,例如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查找带有 的 HTML 元素id='map',该元素在状态模板上声明。

现在,对于实际问题,这是否与某种AngularJS 服务无法访问 HTML 模板有关?我在这件事上找不到任何东西,但我认为服务不直接访问视图是有意义的......
如果是,我应该探索什么样的解决方法?我已经研究过了leaflet-directive,但它似乎没有提供以我想要的灵活性添加和删除自定义回调的可能性(例如,当我使用 Leaflet-Freedraw 添加免费绘图功能时,事情变得复杂了)。

我考虑leaflet.map过直接使用HTMLElement元素的参数,但我仍然无法使其工作 - 尽管有可能我没有通过应该传递的内容。

4

1 回答 1

5

发生的情况是,此时L.Map尝试从您的服务访问 DOM,模板仍然可用。通常服务被加载并注入控制器,控制器初始化它们的作用域,然后模板被初始化并添加到 DOM。你会看到你是否会在地图初始化上设置一个很大的超时时间,它会发现它是 DOM 元素。但这是一个非常丑陋的 hack。在 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]);
      }
    };
  }
]);

这样,initializeMap只有在实际的 DOM 元素可用时才会调用该方法。但它给你带来了另一个问题。在你的控制器初始化的那一刻,你的服务还没有准备好。你可以通过使用 promise 来解决这个问题:

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

于 2015-11-30T14:23:37.477 回答