Matt Grande
Matt Grande

Reputation: 12157

Initializing an Angular Directive in JavaScript

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

Answers (2)

Josh
Josh

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

Chandermani
Chandermani

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

Related Questions