Correct way to compile angular template to html, convert result to string
annotation
Hi I am using angular to render documents, I have a view model that contains the data that needs to go into the document and I have an angular template that represents the document. The template is valid angular-html markup which is later rendered using angular $ compile , here is the directive I use to render documents for presentation purposes:
angular.module('app').directive('render', function ($compile, server) {
return {
restrict: 'E',
link: function ($scope, $element, $attributes) {
var scope;
server.resolve().then(function (repo) {
var _template, _constants, _variables, _substitutes;
var render = function () {
if (_template) {
$scope.repo = repo;
var references = repo.references;
if (_constants) {
for (var constantName in _constants) {
$scope[constantName] = references[_constants[constantName]];
}
}
if (_variables) {
for (var variableName in _variables) {
var substitute = _substitutes[variableName];
var variableValue = _variables[variableName];
var reference = repo.references[substitute];
if (reference) {
if (reference.table === variableValue) {
$scope[variableName] = reference;
} else {
throw new Error('Invalid reference type');
}
}
}
}
if (scope) scope.$destroy();
scope = $scope.$new();
var element = angular.element('<div class="print"></div>');
element.html(_template);
$element.empty();
$element.append(element);
$compile(element)(scope);
}
};
$scope.$watch($attributes.template, function (template) {
_template = template;
render();
});
$scope.$watch($attributes.constants, function (constants) {
_constants = constants;
render();
});
$scope.$watch($attributes.variables, function (variables) {
_variables = variables;
render();
});
$scope.$watchCollection($attributes.substitutes, function (substitutes) {
_substitutes = substitutes;
render();
});
});
}
};
});
Question
I need to make a paper copy of the document, in other words, I need to substitute the values โโof the view model into the document template, convert the result to a string, and put it in a variable. I can't use a directive for this, angular $ compile is a really heavy function to call, it creates a clock under the hood, I don't need the whole shebang, I just need to replace the values. What would be the best way to do this?
Thank you in advance
source to share
With your advice for $interpolate
I could complete my demo for your question.
It disables the service for storing the interpolated pattern in the database to keep the demo focused on the problem.
So, as I understand it, the difference between $compile
and $interpolate
is as follows:
-
$compile
: Creates DOM elements with angular binding to scope. This is what you would normally use to make your DOM for two-way binding, etc. Most of the time you don't call it manually, because if you addtemplate
ortemplateUrl
to direcive definition object, it will automatically start$compile
. -
$interpolate
: it is very similar to compilation with the only difference that it will return the wiht-out angular DOM element bindings.
You can see the difference if you look at the rendering of the html markup. The compiled templates have a class ng-binding
in the markup and the other only has static html without that class.
So, as you mentioned, $interpolate
this is a way to get a compiled string that you can easily store in a database using a service $http
.
Please see the demo below or in this jsfiddle .
angular.module('myApp', [])
.directive('render', Render);
var templateStore = [];
function Render($compile, $interpolate) {
return {
restrict: 'E',
controllerAs: 'render',
controller: function () {
this.hello = 'hello from controller';
//console.log($templateCache.get('testTemplate'));
},
compile: function (tElem, tAttrs) {
return function (scope, element, attrs, controllers) {
//controllers.hello = 'hello from controller';
//console.log(controllers);
var template = angular.element(
document.getElementById('template.html')).html(),
compiled = $compile(template)(scope),
obj = {
render: {
hello: "hello from 'fake' controller"
},
hello: 'hello from other object.'
};
scope.hello = "Hello from scope";
element.replaceWith(compiled);
var result = $interpolate(template)(scope);
templateStore.push(result);
var result = $interpolate(template)(obj);
templateStore.push(result);
//console.log(result);
//console.log(templateStore[0]);
$('#test').append( // append just to test the saved template
templateStore[0]);
$('#test2').append( // append just to test the saved template
templateStore[1]);
};
}
}
}
Render.$inject = ['$compile', '$interpolate'];
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp">
<script type="text/ng-template" id="template.html">
<div>
<p>controllerAs: {{render.hello}}</p>
scope: {{hello}}
</div>
</script>
<h2>Compiled template with binding</h2>
<render></render>
<h2>The following is a string copy from above template with-out binding</h2>
<div id="test"></div>
<h2>You can also $interpolate a object with the following result (also no binding)</h2>
<div id="test2"></div>
</div>
source to share