简体   繁体   中英

A proper way to compile angular template into html, convert result into string

Abstract

Hi, I'm using angular to render documents, I have the view-model that contains the data which should go into document, and I have angular template that represents the document. The template is valid angular-html markup that is later rendered using angular's $compile , here is 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 hard-copy of the document, in other words I need to substitute the view-model values into document template, convert result into string and put it into variable. I can't use directive for that, angular's $compile is really heavy function to call, it creates watches under the hood, I don't need whole shebang, I just need to substitute values. What would be the best way to do that?

Thank you in advance

With your tip for $interpolate I could finalize my demo for your question.

It's with-out a service for storing the interpolated template into database to keep the demo focused on the issue.

So as I've understood, the difference between $compile and $interpolate is the following:

  • $compile : Creates DOM elements with angular binding to scope. That's what you would normally use to render your DOM to have two-way binding etc. working. In most cases you don't call it manually because if you add template or templateUrl to the direcive definition object it will run $compile automatically.

  • $interpolate : It is pretty similar to compile with the only difference that it will return the DOM elements wiht-out angular bindings.

You can see the difference if you have a look at the rendered html markup. Compiled templates have ng-binding class in the markup and the other is just static html with-out that class.

So as you mentioned $interpolate is the way to go to get the compiled string that you can easily store in the database with a $http service.

Please have a look at the demo below or at 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> 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM