Escape HTML text in an AngularJS directive

Is there an angular JS command that will do HTML escaping on text? I am processing a custom directive and have need to escape some of the output which it generates.

Internally the AngularJS sanitzer uses a encodeEntities function, but does not expose it. I know I could duplicate the function, but it seems like there should be a standard way of doing this.


Use-Case: I have a custom directive which does language localization. This directive uses a key lookup from a data file to find language text. In some cases this text is allowed to contain HTML, and/or the directive produces HTML to improve the resulting visual formatting. In addition this directive takes Angular expressions as parameters and uses them as replacements for tokens in the strings. I need to encode these parameters as they may not be HTML safe.

The directive is called as an attribute, for example i18n-html='welcome_text_html,1+1,user.name'. The directive then formats the string as described and uses element.html to update the DOM node.

This answer is about escaping, not sanitizing HTML. There are two approaches:

  1. As mentioned by @maniekq, if you can work on the DOM, do:

    element.text( scope.myValue );
    
  2. From this answer, you can use this code from mustache.js and e.g. create an angular filter:

    angular.module('myModule').filter('escapeHtml', function () {
    
        var entityMap = {
            "&": "&",
            "<": "&lt;",
            ">": "&gt;",
            '"': '&quot;',
            "'": '&#39;',
            "/": '&#x2F;'
        };
    
        return function(str) {
            return String(str).replace(/[&<>"'\/]/g, function (s) {
                return entityMap[s];
            });
        }
    });
    

There are two ways to do HTML sanitization in AngularJS. The first is by using the ngBindHtml directive and the second by using the $sanitize service.

function MyCtrl ( $scope, $sanitize ) {
  $scope.rawHtml = "<div><script></script></div>";
  $scope.sanitizedHmtl = $sanitize( $scope.rawHtml );
}

Then these two are functionally equivalent:

<div ng-bind-html="rawHtml"></div>
<div ng-bind-html-unsafe="sanitizedHtml"></div>

If used in a directive, as in your question, you can simply insert the sanitized HTML:

element.html( scope.sanitizedHtml );

But in most cases when writing directives, you'd have this in a template and use ngBindHtml, as above. But it works for the corner cases.

Sanitizing is one thing, but to display all characters and not "execute" HTML code I have used "text" function to set value.

In your directive, to set value, instead of writing:

element.html( scope.myValue );

write:

element.text( scope.myValue );

There are two separate issues with escaping HTML. The first issue is that entities need to be encoded, and the second issue is that the result needs to be trusted so the data can be used as html bindings. Adding the following code to your controller(s) provides a solution for both issues using the $sce service.

CoffeeScript Solution:

MyApp.controller('MyController', ['$scope','$sce',($scope,$sce) ->

  ###
  ...
  ###

  $scope.html5Entities = (value) ->
    value.replace(/[\u00A0-\u9999<>\&\'\"]/gim, (i) ->
      '&#' + i.charCodeAt(0) + ';'
    )

  $scope.trustAsHtml = (value) ->
    $sce.trustAsHtml(value)

  ###
  ...
  ###

])    


Javascript Solution:

MyApp.controller('MyController', ['$scope','$sce', function($scope,$sce) {

  /* ... */

  $scope.html5Entities = function(value) {
    return value.replace(/[\u00A0-\u9999<>\&\'\"]/gim, function(i) {
          return '&#' + i.charCodeAt(0) + ';'
        })
  };

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

  /* ... */

}]);


The first function html5Entities does the actual entity encoding, while the second function trustAsHtml marks a string as safe to use in Angular for HTML bindings. Both versions require that the $sce service be included in your controller.

Example usage:

<div ng-bind-html="trustAsHtml((html5Entities(product.title) | highlight: $select.search))"></div>

See related issues:

You can use encodeEntities() function in ngSanitize to escape & < > etc.