Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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 value becomes 'value &ampgt; 3'.

ng-bind doesn't support the following:

value > 3 will be rendered for ngBind, whereas the browser renders the same content as value > 3.

http://jsfiddle.net/HKahG/2/

Ng:bind <div ng-bind="model"></div> 
Ng:bind-html <div ng-bind-html="model"></div>
<div> From Div: value &gt; </div>

Why is this default browser behavior not present in ng-bind?. I don't want to use ng-bind-html (has issues with value < and it is not a html) or ng-bind-unsafe-html.

My application has dynamic key-value fields which will be displayed in different parts of the application. So it will require additional overhead to use a separate directive or decorator to display all string fields than to use ngBind.

Questions:

1) Is there any other way of doing the same without using an additional directive, or is this the right way of handling encoded data?

2) Can I override the behavior of ng-bind or decorate it by default?

like image 930
DarkKnight Avatar asked Oct 09 '13 06:10

DarkKnight


People also ask

What is the synonym of escaping?

Some common synonyms of escape are avoid, elude, eschew, evade, and shun.

What does escaping time mean?

What Does Escape Time Mean? Escape time refers to the length of time that is available to (and necessary for) an individual to escape from a specific hazardous situation.

How do you use escape in a sentence?

The prisoners attempted a daring escape. He celebrated his escape from his boring job with a long vacation. She had a lucky escape when she wasn't injured in the accident. She managed to avoid serious injury, but it was a narrow escape.

What type of word is escaped?

escape used as a verb: To avoid (any unpleasant person or thing); to elude, get away from. "He only got a fine and so escaped going to jail." To avoid capture; to get away with something, avoid punishment. "Luckily, I escaped with only a fine."


1 Answers

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.

like image 132
J. Bruni Avatar answered Sep 17 '22 20:09

J. Bruni