【问题标题】:How to initialize an AngularJS directive model from child elements?如何从子元素初始化 AngularJS 指令模型?
【发布时间】:2013-03-28 18:25:17
【问题描述】:

我正在尝试使用子元素初始化 AngularJS 指令中的一些数据。在这种情况下,<map> 元素被替换为使用传单连接的<div>。我试图弄清楚指令compilelink 函数中是否有某种方法可以从声明的子元素中填充markers 集合,如下所示:

<div ng-app="dashboard">
<div ng-controller="DashboardCtrl">
    <map id="devicemap" tile-handle="test.map-fy18v14h" min-zoom="3" max-zoom="9" markers="markers">
        <marker lat="44" lng="-88.5" description="From the Server (Razor)" />
        <marker lat="44.1" lng="-88.6" description="From the Server 2 (Razor)" />
    </map>
</div>

在指令中,我想遍历 &lt;marker&gt; 元素以填充集合。这应该在编译中发生吗?或者,我是否误以为我可以在插入实际模板之前访问我的“假 DOM”?

module.directive('map', function () {
return {
    restrict: "E",
    replace: true,
    scope: {
        markers: "=markers"
    },
    template: '<div class="map"></div>',
    link: function link(scope, elm, attributes) {
        var map = L.map(attributes.id, {
            dragging: true,
            zoomAnimation: true
        }).setView([45.505, -88.09], 6);
        L.tileLayer('http://{s}.tiles.mapbox.com/v3/' + attributes.tileHandle + '/{z}/{x}/{y}.png', {
            attribution: "<a href='http://mapbox.com/about/maps' target='_blank'>Terms & Feedback</a>",
        }).addTo(map);

        // This is where I am stuck... is there a way to get the "marker" elements?   
        // the following does not work...
        var markerElements = elm.children('marker');  

        // now would like to loop over markerElements, grab the attributes and add them 
        // to the map (and/or the markers collection).

    };
});

我可以使用 ajax 调用来填充标记,但是,这种技术将允许我在第一次请求页面时预先填充服务器上的数据。

【问题讨论】:

  • 因为您使用的是template(和replace: true),所以在链接函数运行时,&lt;marker&gt; 标记已被删除。这就是链接功能找不到它们的原因。
  • 这是有道理的。有没有办法在原始 DOM 被替换之前访问它?
  • 你可以在编译函数中这样做,但你不能使用template(或replace: true),否则编译函数会看到应用的模板而不是原始的DOM。在 compile 函数中,您可以在完成 DOM 修改后使用 replaceWith()。示例:stackoverflow.com/a/10646761/215945

标签: asp.net-mvc angularjs angularjs-directive


【解决方案1】:

好的,在 Mark Rajcok 的提示下,我想出了一个解决方案。这允许我使用在服务器上生成的自定义 HTML 元素在地图上设置标记。我需要使用list 变量来存储compile 函数中收集的数据。不确定是否有使用 Angular 的更简洁的方法。

HTML/Razor

<div ng-app="dashboard">
    <div ng-controller="DashboardCtrl">
        <map id="devicemap" tile-handle="example.map-fy18v14h" min-zoom="3" max-zoom="9" markers="markers">
        @foreach (var location in Model.Locations)
        {
           <marker lat="@location.Lat" lng="@location.Lng" description="@location.Description" ></marker>                                   
        }
        </map>
     </div>
</div>

控制器

var module = angular.module('dashboard', ['map-directive']);
module.controller("DashboardCtrl", function ($scope, $http) {
     $scope.markers = [];
});

指令

var mapDirective = angular.module("map-directive", []);

mapDirective.directive('map', function () {

    var list = [];

    function link (scope, elm, attributes) {
        var map = L.map(attributes.id, {
            dragging: true,
            zoomAnimation: true
        }).setView([45.505, -88.09], 6);

        scope.markers = list;

        L.tileLayer('http://{s}.tiles.mapbox.com/v3/' + attributes.tileHandle + '/{z}/{x}/{y}.png', {
            attribution: "<a href='http://mapbox.com/about/maps' target='_blank'>Terms & Feedback</a>",
        }).addTo(map);

        scope.$watch('markers', function (newValue, oldValue) {
            if (newValue)
                angular.forEach(scope.markers, function (marker) {
                    L.marker([marker.lat, marker.lng], { draggable: marker.draggable }).addTo(map).bindPopup(marker.description);
                });
        });
    }

    return {
        restrict: "E",
        scope: {
            markers: "=markers"
        },

        compile: function(tElement, tAttrs, transclude) {

            console.log(tElement);
            console.log(tElement.find("marker"));

            var markers = tElement.find("marker");


            angular.forEach(markers, function (marker) {
                list.push({ lat: marker.attributes.lat.value, lng: marker.attributes.lng.value, description: marker.attributes.description.value});
            });

            var htmlText = '<div class="map" id="' + tAttrs.id + '" ></div>';
            tElement.replaceWith(htmlText);
            return link;
        }
    };

});

【讨论】:

  • list 将由应用程序中的所有 map 指令共享。如果您打算使用多个map,那么您需要有多个列表,或者将list 从一个数组转换为一个对象,其中每个属性是map 的id,每个属性value 是一个数组。
【解决方案2】:

其实你可以在 templateUrl 中使用 derective。 只需将 ng-transclude 放在那里的任何元素上,它就会拥有所有原始子元素。 然后在链接函数中,你可以读取那些 DOM 元素,做任何你想做的事情并清理它们。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-03-01
    • 1970-01-01
    • 2013-12-06
    • 1970-01-01
    • 1970-01-01
    • 2018-11-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多