I have a div element with ng-bind directive:
<div ng-bind="sometext"></div>
I have a directive that gets an element, checks its value / text and adds a color to the element according to the content. I am using this directive like that:
<div ng-bind="sometext" my-directive></div>
The problem is that on the time the directive is executing, there is no value or text on the div because ng-bind didn't happened yet.
I am getting the text using element.text().
Any idea how to make the text available inside my directive?
The ng-bind directive tells AngularJS to replace the content of an HTML element with the value of a given variable, or expression. If the value of the given variable, or expression, changes, the content of the specified HTML element will be changed as well.
ngModel usually use for input tags for bind a variable that we can change variable from controller and html page but ngBind use for display a variable in html page and we can change variable just from controller and html just show variable. Save this answer.
firstName expression in the application's scope are also reflected instantly in the DOM by Angular. ng-bind is about twice as fast as {{}} expression bind. ng-bind places a watcher on the passed expression and therefore the ng-bind only applies, when the passed value actually changes.
The ng-bind-html Directive in AngularJS is used to bind the innerHTML of an HTML element to application data and remove dangerous code from the HTML string. $sanitize service is a must for the ng-bind-html directive. It is supported by all HTML elements.
Your directive may be running before ngBind
has bound it's value - both your directive and ngBind
are priority 0 so either could run first, more on that in a moment- but let's look at the ngBind
source code to see the root of the problem:
var ngBindDirective = ngDirective(function(scope, element, attr) {
element.addClass('ng-binding').data('$binding', attr.ngBind);
scope.$watch(attr.ngBind, function ngBindWatchAction(value) {
element.text(value == undefined ? '' : value);
});
});
We see that ngBind
doesn't immediately update the DOM, but rather places a watch on the ngBind
attribute. So the element won't be updated until that watch is run on the next $digest
cycle (which is why a $timeout
works).
So one option is to mimic ngBind
and place your own watch on it's attribute- then you'll be updated whenever the ngBind
result changes:
angular.module('myApp').directive('myDirective', function() {
return {
priority: 1,
link: function(scope,element,attrs) {
scope.$watch(attrs.ngBind, function(newvalue) {
console.log("element ",element.text());
});
}
};
});
You'll note I set priority to 1. You do need to be sure that this directive's watch is placed after the ngBind
watch in the watch queue. That will ensure the element has been updated by ngBind
first.
By default a directive's link function runs post-link, so as the $compile
docs note:
Directives with greater numerical priority are compiled first. Pre-link functions are also run in priority order, but post-link functions are run in reverse order.
Therefore, since ngBind
is priority 0, anything over 0 will ensure your directive's watch will come after the ngBind
watch..
demo fiddle
Edit 2
The other option is to use ng-class
or ng-style
for changing the color of the text. Then you don't have to create a new directive at all.
Original Answer
I would not depend on the ng-bind
directive at all... This seems much cleaner in my opinion.
<div ng-bind="someModel" my-directive="someModel"></div>
And then define your directive as...
angular.module('myApp').directive('myDirective', function() {
return {
link: function(scope, element, attrs) {
scope.$watch(attrs.myDirective, function(newValue, oldValue) {
// Your Code here...
});
}
};
});
This way you can use your directive even if you don't have an ng-bind
on the element (for example, if you use curly braces instead).
<div my-directive="someModel">{{someModel}}</div>
Alternatively you can use attrs.$observe(...)
(documentation) instead of scope.$watch(...)
.
<div ng-bind="someModel" my-directive="{{someModel}}"></div>
and
angular.module('myApp').directive('myDirective', function() {
return {
link: function(scope, element, attrs) {
attrs.$observe('myDirective', function(interpolatedValue) {
// Your Code here...
});
}
};
});
You can find more information about the differences between scope.$watch(...)
and attrs.$observe()
here.
Edit
Given that your directive is basically mutating the DOM after the ng-bind
directive, why not skip the ng-bind
all together?
<div my-directive="{{someModel}}"></div>
and
angular.module('myApp').directive('myDirective', function() {
return {
link: function(scope, element, attrs) {
attrs.$observe('myDirective', function(interpolatedValue) {
if (interpolatedValue) {
// Modify interpolatedValue if necessary...
}
element.text(interpolatedValue == undefined ? '' : interpolatedValue);
});
}
};
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With