I am trying to initialize some data in an AngularJS directive with child elements. In this case, the <map> element is replaced with a <div> that gets hooked up using leaflet. I was trying to figure out if there is some way in the directive compile or link function to populate the markers collection from declared child elements, something like this:
<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>
In the directive, I would like iterate over the <marker> elements to populate a collection. Should this happen in compile? Or, am I misguided that I can access my "fake DOM" prior to the actual template being inserted?
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).
};
});
I am able to populate the markers using an ajax call, however, this technique would allow me to pre-populate the data on the server when the page is first requested.
Ok, with the hint from Mark Rajcok, I have come up with a solution. This allows me to set up the markers on the map using custom HTML elements that are generated on the server. I needed to use the list variable to store off the data collected in the compile function. Not sure if there is a cleaner way to do this with 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>
Controller
var module = angular.module('dashboard', ['map-directive']);
module.controller("DashboardCtrl", function ($scope, $http) {
$scope.markers = [];
});
Directive
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;
}
};
});
Actually you can use derective with templateUrl. Just put ng-transclude on any element there and it will have all original children elements as its own. Then in link function you can read those DOM elements, do whatever you ant and clean them up.