Skip to content Skip to sidebar Skip to footer

Escaping & > Characters In Ng-bind In AngularJs

I have a use case, where we can have '&' and '>' characters in a string. eg. Johnson & Johnson, value > 3. So while the response from server is encoded, hence the val

Solution 1:

EDIT: please, go straight to the bottom of the answer to get the best version; the answer is at chronological order; I got the optimal code after a few iterations, at the end. Thank you.

  • Can I override the behaviour of ng-bind or decorate it by default ?

Yes. I've done a very simple implementation which makes ng-bind to behave as you want. Well... I'm not sure if this is exactly what you want, but at least it does what I've understood you want.

Working fiddle: http://jsfiddle.net/93QQM/

And here is the code:

module.directive('ngBind', function() {
    return {
        compile: function(tElement, tAttrs) {
            tAttrs.ngBind = 'myBind(' + tAttrs.ngBind + ')';
            return { 
                pre: function(scope) {
                    scope.myBind = function(text) {
                        return angular.element('<div>' + text + '</div>').text();
                    }
                }
            };
        }
    }
});

This is not exactly an "additional directive" - this is the way to "override the behaviour of ng-bind". It does not add a new directive, it just extends behaviour of existent ngBind directive.

At the compile function, we modify the value of the ng-bind attribute, wrapping it into a function call. With this, we have access to the original model value, and the opportunity to return it modified.

We make the function available through the scope in the pre-linking phase, because if we do this in the post-linking phase, the function will be available only after the original ngBind directive has retrieved the value from the attribute (which will be an empty string, because the function wil not be found).

The myBind function is simple and smart: it creates an element, and the text is used - unchanged - as the element body, only to be immediately retrieved through the text function - which will return the contents just as "the browser renders" it.

This way, you can use ngBind as usual, like <div ng-bind="model.content" />, but have this modified behaviour.


Improved version

Instead of attaching the myBind function to every scope where ngBind is applied, at every pre-linking phase, we can attach it only once to the $rootScope, making it immediately available for all scopes.

New working fiddle: http://jsfiddle.net/EUqP9/

New code:

module.directive('ngBind', ['$rootScope', function($rootScope) {
    $rootScope.myBind = function(text) {
        return angular.element('<div>' + text + '</div>').text();
    };
    return {
        compile: function(tElement, tAttrs) {
            tAttrs.ngBind = 'myBind(' + tAttrs.ngBind + ')';
        }
    };
}]);

Much cleaner than the previous version! Of course, you can change myBind function name to any other name you want. The "cost" of the feature is this: have this simple function added to the root scope - it is up to you to decide if it worths the price.


Yet another version

Influenced by Chemiv's answer... why not remove the function from any scope and make it a filter instead? It also works.

Yet another new working fiddle: http://jsfiddle.net/hQJaZ/

And the new code:

module.filter('decode', function() {
    return function(text) {
        return angular.element('<div>' + text + '</div>').text();
    };
}).directive('ngBind', function() {
    return {
        compile: function(tElement, tAttrs) {
            tAttrs.ngBind += '|decode';
        }
    };
});

Now you have three options to choose from the menu.


Solution 2:

This is HTML:

&gt;

It may not have HTML tags, but it's still HTML. If you want to use ng-bind, your server needs to return unencoded text. Ie, > instead of &gt;.

Use ng-bind-html or modify your server to return plain text without html encoding it first.

Edit: Quick demo that illustrates the use of &gt; and > in JavaScript:

div1.innerHTML = "&gt;";  // write HTML
div2.textContent = ">";   // write plain text
console.log(div1.innerHTML === div2.innerHTML);
console.log(div1.textContent === div2.textContent);

http://jsfiddle.net/XhEcV/


Solution 3:

ng-bind uses .text() method to replace text and while your code contains &gt; which is HTML markup it is not correctly rendered by ng-bind. You should use ng-bind-html in this place as you are actually entering HTML content. Otherwise you can replace > by regex to '>'.

ex :- model = model.replace(/&gt;/g, '>');

But in this case you have to replace all HTML markups which is not needed since ng-bind-html is already working fine in your case.


Solution 4:

Yes , let's "decorate" it with a filter:

.filter("decode",function(){
    return function(str){         
      var el = document.createElement("div");
      el.innerHTML = str;
      str =   el.textContent || el.innerText;
      return str;        
    }
});

And use it like: <div ng-bind="model|decode"></div>

Working example: http://jsfiddle.net/HKahG/5/

Inspired by this answer: https://stackoverflow.com/a/784698/1206613


Solution 5:

I remember a directive named ngBindHtmlUnsafe available for such use cases.

http://code.angularjs.org/1.0.8/docs/api/ng.directive:ngBindHtmlUnsafe

Please refer to this. Not sure if this is available in later unstable releases. This is link to the latest stable release available.


Post a Comment for "Escaping & > Characters In Ng-bind In AngularJs"