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.