[html] With ng-bind-html-unsafe removed, how do I inject HTML?

I'm trying to use $sanitize provider and the ng-bind-htm-unsafe directive to allow my controller to inject HTML into a DIV.

However, I can't get it to work.

<div ng-bind-html-unsafe="{{preview_data.preview.embed.html}}"></div>

I discovered that it is because it was removed from AngularJS (thanks).

But without ng-bind-html-unsafe, I get this error:

http://errors.angularjs.org/undefined/$sce/unsafe

This question is related to html angularjs

The answer is


You can use filter like this

angular.module('app').filter('trustAs', ['$sce', 
    function($sce) {
        return function (input, type) {
            if (typeof input === "string") {
                return $sce.trustAs(type || 'html', input);
            }
            console.log("trustAs filter. Error. input isn't a string");
            return "";
        };
    }
]);

usage

<div ng-bind-html="myData | trustAs"></div>

it can be used for other resource types, for example source link for iframes and other types declared here


I've had a similar problem. Still couldn't get content from my markdown files hosted on github.

After setting up a whitelist (with added github domain) to the $sceDelegateProvider in app.js it worked like a charm.

Description: Using a whitelist instead of wrapping as trusted if you load content from a different urls.

Docs: $sceDelegateProvider and ngInclude (for fetching, compiling and including external HTML fragment)


You indicated that you're using Angular 1.2.0... as one of the other comments indicated, ng-bind-html-unsafe has been deprecated.

Instead, you'll want to do something like this:

<div ng-bind-html="preview_data.preview.embed.htmlSafe"></div>

In your controller, inject the $sce service, and mark the HTML as "trusted":

myApp.controller('myCtrl', ['$scope', '$sce', function($scope, $sce) {
  // ...
  $scope.preview_data.preview.embed.htmlSafe = 
     $sce.trustAsHtml(preview_data.preview.embed.html);
}

Note that you'll want to be using 1.2.0-rc3 or newer. (They fixed a bug in rc3 that prevented "watchers" from working properly on trusted HTML.)


You do not need to use {{ }} inside of ng-bind-html-unsafe:

<div ng-bind-html-unsafe="preview_data.preview.embed.html"></div>

Here's an example: http://plnkr.co/edit/R7JmGIo4xcJoBc1v4iki?p=preview

The {{ }} operator is essentially just a shorthand for ng-bind, so what you were trying amounts to a binding inside a binding, which doesn't work.


For me, the simplest and most flexible solution is:

<div ng-bind-html="to_trusted(preview_data.preview.embed.html)"></div>

And add function to your controller:

$scope.to_trusted = function(html_code) {
    return $sce.trustAsHtml(html_code);
}

Don't forget add $sce to your controller's initialization.


Strict Contextual Escaping can be disabled entirely, allowing you to inject html using ng-html-bind. This is an unsafe option, but helpful when testing.

Example from the AngularJS documentation on $sce:

angular.module('myAppWithSceDisabledmyApp', []).config(function($sceProvider) {
  // Completely disable SCE.  For demonstration purposes only!
  // Do not use in new projects.
  $sceProvider.enabled(false);
});

Attaching the above config section to your app will allow you inject html into ng-html-bind, but as the doc remarks:

SCE gives you a lot of security benefits for little coding overhead. It will be much harder to take an SCE disabled application and either secure it on your own or enable SCE at a later stage. It might make sense to disable SCE for cases where you have a lot of existing code that was written before SCE was introduced and you're migrating them a module at a time.


The best solution to this in my opinion is this:

  1. Create a custom filter which can be in a common.module.js file for example - used through out your app:

    var app = angular.module('common.module', []);
    
    // html filter (render text as html)
    app.filter('html', ['$sce', function ($sce) { 
        return function (text) {
            return $sce.trustAsHtml(text);
        };    
    }])
    
  2. Usage:

    <span ng-bind-html="yourDataValue | html"></span>
    

Now - I don't see why the directive ng-bind-html does not trustAsHtml as part of its function - seems a bit daft to me that it doesn't

Anyway - that's the way I do it - 67% of the time, it works ever time.


Instead of declaring a function in your scope, as suggested by Alex, you can convert it to a simple filter :

angular.module('myApp')
    .filter('to_trusted', ['$sce', function($sce){
        return function(text) {
            return $sce.trustAsHtml(text);
        };
    }]);

Then you can use it like this :

<div ng-bind-html="preview_data.preview.embed.html | to_trusted"></div>

And here is a working example : http://jsfiddle.net/leeroy/6j4Lg/1/


You can create your own simple unsafe html binding, of course if you use user input it could be a security risk.

App.directive('simpleHtml', function() {
  return function(scope, element, attr) {
    scope.$watch(attr.simpleHtml, function (value) {
      element.html(scope.$eval(attr.simpleHtml));
    })
  };
})