2

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>' );

2 Answers 2

2

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.

Sign up to request clarification or add additional context in comments.

1 Comment

Holy crap! You just simplified my code a whole lot! I figured there had to be an easier way to do what I was doing, but couldn't find it.
1

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.

4 Comments

Okay, I've been trying to get the $compile to work, but I was having trouble with the scope. I'll give this a shot...
It's a bit hard to tell based on the context I'm seeing in your question. I can't quite tell how your loop to add marker popups relates the the original directive you have shown.
I'm putting the 'activities' in a list on the page, and also want the same information to be displayed when you click a map marker, if that makes sense? So, currently they're being displayed on the page, but I can't get them to display on the map.
So, I took Chandermani's advice and switched to an ngInclude, rather than a directive, and your code's got me most of the way there... but all I'm getting in the view is this comment: <!-- ngInclude: '/templates/activity-incident.html' --> (which is doubly strange because I'm passing the $compile this: '<li ng-include="\'/templates/activity-incident.html\'"></li>'). Any ideas?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.