Reputation: 12157
I have a directive in my template. It's working great:
<ul class="activity-stream">
<my-activity-stream-item ng-repeat="activity in vm.activities" activity="activity"></my-activity-stream-item>
</ul>
I'd basically like to include the same HTML in that template as a popup in a Leaflet Map, but I have no idea how to create that in code. Here's what I tried:
for (i = 0; i < activities.length; i++) {
var activity = activities[i];
var marker = L.marker([activity.location.lat, activity.location.lng]);
marker.type = activity.type;
marker.bindPopup( '<my-activity-stream-item activity="activity"></my-activity-stream-item>' );
marker.addTo( map );
}
I didn't really expect that to work, I feel like I have to pass the scope in somehow... but I'm at a complete loss as to how to do it.
var app = angular.module('myPortal');
app.factory('TemplateService', TemplateService);
app.directive('myActivityStreamItem', myActivityStreamItem);
function myActivityStreamItem( $compile, TemplateService ) {
return {
restrict: 'E',
link: linker,
transclude: true,
scope: {
activity: '='
}
};
function linker(scope, element, attrs) {
scope.rootDirectory = 'images/';
TemplateService.getTemplate( 'activity-' + scope.activity.type ).then(function(response) {
element.html( response.data );
$compile(element.contents())(scope);
});
}
}
function TemplateService( $http ) {
return {
getTemplate: getTemplate
};
function getTemplate( templateName ) {
return $http.get('/templates/' + templateName + '.html');
}
}
(Note - I've only been using Angular for about a week, so please let me know if you think I've done this completely wrong)
EDIT: I took Chandermani's advice and switched my directive to an ngInclude
:
<ul class="activity-stream">
<li ng-repeat="activity in vm.activities" ng-include="'/templates/activity-' + activity.type + '.html'"></li>
</ul>
This works great! I also tried to use Josh's advice to compile the HTML in JavaScript, however I'm not quite there...
var link = $compile('<li ng-include="\'/templates/activity-' + activity.type + '.html\'"></li>');
var newScope = $rootScope.$new();
newScope.activity = activity;
var html = link( newScope );
marker.bindPopup( html[0] );
This results in the popup appearing, but the HTML contained within the popup is a comment: <!-- ngInclude: '/templates/activity-incident.html' -->
Do I have to pass it the activity in the li
somehow?
Edit 2: Got it! As noted in Issue #4505, you need to wrap the snippet in something, so I wrapped my ngInclude
in a div
:
var link = $compile( '<div><ng-include src="\'/templates/activity-incident.html\'"></ng-include></div>' );
Upvotes: 2
Views: 103
Reputation: 44916
Anytime you want to add raw HTML to the page and have Angular process it, you need to use the $compile
service.
Calling $compile
on a template will return a linking function which can then be used to bind a scope object to.
var link = $compile('<span>{{someObj}}</span>');
Linking that function to a scope
object will result in an element that can then be appended into the DOM.
//Or the scope provided by a directive, etc...
var newScope = $rootScope.$new();
var elem = link(newScope);
//Could also be the element provided by directive
$('someSelector').append(elem);
That's the basic flow you need to be able to tell Angular to process your DOM element. Usually this is done via a directive, and that's probably what you need in this case as well.
Upvotes: 1
Reputation: 42669
Not sure i have understood your problem, but what you can do is to use ng-include
directive and it can take a template expression to dynamically load a template. Something like:
<ul class="activity-stream">
<li ng-repeat="activity in vm.activities" ng-include="'/templates/activity-' + activity.type + '.html'"></li>
</ul>
You may not require a directive here.
Upvotes: 2