Dónal
Dónal

Reputation: 187399

programmatically compile template and append to element

In an Angular 1.4.7 app I want to programmatically compile a string of HTML, passing it a scope. This compilation is performed inside a directive, and I want to append the result of the compilation to a child of the directive's element.

I'm current attempting to do this like so:

 // htmlTemplate is a string of HTML that contains expressions,
 // directives, etc.
 var htmlContentScope = {foo: 'foo', bar: 'bar'};
 var compiledHtml = $compile(htmlTemplate)(htmlContentScope);
 var htmlContentTarget = $element.find('.html-content');
 htmlContentTarget.html(compiledHtml);

However this results in the following error

scope.$new is not a function

Possibly the reason for this is that htmlContentScope is a plain-old JS object, rather than an Angular scope object?

Upvotes: 2

Views: 660

Answers (1)

Jeff Bowman
Jeff Bowman

Reputation: 95754

Correct, you need to pass in an Angular Scope, not an normal object or hash. This is important so that Angular can enforce watches, keep track of the scope's ID number in internal data structures, and access the root scope.

As in the "Usage" section of the $compile docs:

Returns

function(scope, cloneAttachFn=, options=)

a link function which is used to bind template (a DOM element/tree) to a scope. Where:

  • scope - A Scope to bind to.
  • ...

So assuming you have access to a scope parameter, because this is likely in a link or postLink function:

var htmlContentScope = scope.$new();
htmlContentScope.foo = 'foo';
htmlContentScope.bar = 'bar';
var compiledHtml = $compile(htmlTemplate)(htmlContentScope);
$element.find('.html-content').html(compiledHtml);

Of course, if this weren't in a directive or if you wanted a clean slate free of parent scope interference, you could extend the $rootScope instead, but in a directive it's much more correct to use the scope you're given.

Upvotes: 1

Related Questions