How to make ng-bind-html compile angularjs code

I am working with angularjs 1.2.0-rc.3. I'd like to include html code into a template dynamically. For that I use in the controller :

html = "<div>hello</div>";
$scope.unicTabContent = $sce.trustAsHtml(html);

In the template I got :

<div id="unicTab" ng-bind-html="unicTabContent"></div>

It works fine for regular html code. But when I try to put angular template it is not interpreted, it is just included in the page. For example I'd like to include :

<div ng-controller="formCtrl">
    <div ng-repeat="item in content" ng-init="init()">
    </div>
</div>

Thanks a lot

Answers:

Answer

This solution doesn't use hardcoded templates, and you can compile Angular expressions embedded within an API response.


Step 1. Install this directive: https://github.com/incuna/angular-bind-html-compile

Step 2. Include the directive in the module.

angular.module("app", ["angular-bind-html-compile"])

Step 3. Use the directive in the template:

<div bind-html-compile="letterTemplate.content"></div>

Result:

Controller Object

 $scope.letter = { user: { name: "John"}}

JSON Response

{ "letterTemplate":[
    { content: "<span>Dear {{letter.user.name}},</span>" }
]}

HTML Output =

<div bind-html-compile="letterTemplate.content"> 
   <span>Dear John,</span>
</div>

For reference sake, here's the relevant directive:

(function () {
    'use strict';

    var module = angular.module('angular-bind-html-compile', []);

    module.directive('bindHtmlCompile', ['$compile', function ($compile) {
        return {
            restrict: 'A',
            link: function (scope, element, attrs) {
                scope.$watch(function () {
                    return scope.$eval(attrs.bindHtmlCompile);
                }, function (value) {
                    element.html(value);
                    $compile(element.contents())(scope);
                });
            }
        };
    }]);
}());
Answer

This is what I've made, no idea if it's the angular wayTM, but it works and is super simple;

.directive('dynamic', function($compile) {
    return {
        restrict: 'A',
        replace: true,
        link: function (scope, element, attrs) {
            scope.$watch(attrs.dynamic, function(html) {
                $compile(element.html(html).contents())(scope);
            });
        }
    };
});

So;

<div id="unicTab" dynamic="unicTabContent"></div>

Edit: I found the angular way, and it's super simple.

$templateCache.put('unicTabContent', $sce.trustAsHtml(html));
<div id="unicTab" ng-include="'unicTabContent'"></div>

Don't need to make your own directives or anything. But it's a bind-once sort of deal, it wont see changes made to your html like the custom directive does.

Answer

As Vinod Louis says in his comment, the best way to do that was to use templates. I had to define a template outside of the regular code, for example I added that code inside of my index.html :

<script type="text/ng-template" id="unic_tab_template.html">
    <div ng-switch on="page">
        <div ng-switch-when="home"><p>{{home}}</p></div>
        <div ng-switch-when="form">
            <div ng-controller="formCtrl">
                <div ng-repeat="item in content">{{item.name}}:{{item.value}}</div>
            </div>
        </div>
        <div ng-switch-default>an error accured</div>
    </div>
</script>

This template is conditional, so depending on the value of $scope.page, it switches between the 3 templates (the third being an error handler). To use it I had :

<div id="unicTab" ng-controller="unicTabCtrl">
    <div ng-include="'unic_tab_template.html'"></div>
</div>

That way my page changes depending on the $scope inside of my unicTabCtrl controller.

To conclude the idea of inserting angularsjs template seams to be difficult to realize ($compile seams to be the solution, but I wasn't able to make it work). But instead you may use conditional templating.

Answer

I was trying to do the same thing and came across this module.

http://ngmodules.org/modules/ng-html-compile

I just included it and then I was able to use "ng-html-compile" instead of "ng-bind-html"

Answer

One way is use a directive for purpose of inserting custom templates that include angular expresssions

<div id="unicTab" unic-tab-content></div>
app.directive("unicTabContent",function(){
   return {
      restrict:"A",
      template:'{{unicTabContent}}'
   }
})
Answer

My solution to similar problem in my current app without using template (not elegant, but working):

directive('ngBindHtmlCompile', ['$compile', function ($compile) {
    return {
        restrict: 'A',
        compile: function compile(tElement, tAttributes, transcludeFn) {
            return function postLink(scope, element, attributes) {
                scope.$watch(function() {
                    return scope.$eval(attributes.ngBindHtml);
                }, function(newValue, oldValue) {
                    $compile(element.children())(scope);
                });
            };
        }
    };
}]);

It requires ngBindHtml on the same element and compiles the element content after it changes with ngBindHtml.

<div id="unicTab" ng-bind-html="unicTabContent" ng-bind-html-compile></div>

ng-html-compile looks similar but at first glance it won't be recalculated when the template content is changing. But I haven't tried it.

Answer

The code below is much simpler using Angular's built-in $interpolate and $sce objects. First inject the $interpolate and $sce Angular objects into your directive as you do anything custom you need in your directive.

amqApp.directive('myDir', ['$interpolate', '$sce', function ($interpolate,$sce ) {...}

Then create all your scoped variables found in your imported html expressions...

$scope.custom = 'Hello World';

Next use $interpolate to process your custom HTML and its expressions...then make sure you use the $sce object to trust it as HTML before binding...

var html = $interpolate('<b>{{custom}}</b>')($scope);    
$scope.data = $sce.trustAsHtml(html);

Finally, in your view, just make sure use an element with the "ng-bind" or "ng-bind-html" on it in your view display. I found the $sce piece wont display the HTML as HTML (sees it as text) if you don't bind it in your html template like this...

<span ng-bind-html="data"></span>

You should see in bold...

Hello World

I used this trick to import in text/HTML with custom angular {{expressions}} from a web.config.

Answer

A lot simplified solution of @clement-roblot based on built-in templates.

Controller:

app.controller('TestCtrl', [
    '$scope',
    '$templateCache',
    function ($scope, $templateCache) {
        $templateCache.put('test.html', '2 + 2 = {{ 2 + 2 }}');
    }
]);

View:

<div ng-include="'test.html'"></div>

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.