Reputation: 80385
I have a controller that has a counter that changes from time to time.
That counter is tied to an attribute of a directive and read inside the link function of that directive.
How can I have a directive run a function each time that attr value changes?
Thanks.
Upvotes: 21
Views: 41111
Reputation: 1867
Use attrs.$observe(key, fn)
. More info at $compile.directive.Attributes
attrs.$observe('counter',function(counter){
});
Related answer: https://stackoverflow.com/a/14907826/2874153
$observe() is a method on the Attributes object, and as such, it can only be used to observe/watch the value change of a DOM attribute. It is only used/called inside directives. Use $observe when you need to observe/watch a DOM attribute that contains interpolation (i.e., {{}}'s). E.g., attr1="Name: {{name}}", then in a directive: attrs.$observe('attr1', ...). (If you try scope.$watch(attrs.attr1, ...) it won't work because of the {{}}s -- you'll get undefined.) Use $watch for everything else.
Upvotes: 12
Reputation: 459
I had to implement this myself and found a solution! Unfortunately, when I tried .$watch, errors were just spewing out on the console. So I used $observe instead.
Here's my solution:
angular.module('app').directive('aDate', [
function() {
return {
template: '<span>{{date}}</span>',
restrict: 'E',
replace: true,
link: function(scope, element, attrs) {
attrs.$observe('date', function (val) {
var d = new Date(val);
element.text(d);
});
}
};
}
]);
The above code changes the scoped date when the date attribute of the element changes!
Cheers!
Upvotes: 3
Reputation: 123861
I am using this aproach:
.directive('mydirective',
[function (){
return {
...
scope: {
id: '@',
},
controller: function ($scope, $element, $attrs) {
$attrs.$observe('id', function(passedId) {
/// do what is needed with passedId
});
...
And the directive used and id passed like this:
<div mydirective id="{{someprop.id}}" />
Upvotes: 41
Reputation: 67296
If you can, change the directive to isolated scope and use the =
definition. This will set up a two-way binding for the scope property:
app.directive('myDirective', function() {
return {
scope: { counter: '=' }
}
});
Upvotes: 3
Reputation: 22171
Inside your corresponding link
function: (assuming your attribute is called counter
and your scope variable is: scope
)
scope.$watch(attrs.counter, function (newTime) {
//do something with the new Time
});
Other way, surely more efficient way:
Inside your directive, set the scope
property as following (it will be isolated so):
scope: { counter: '@'}
The counter
would automatically be observed providing the current value as long as the link
function is called.
'@'
better than '='
here since you I suppose you don't set the counter to a new value in your directive, meaning you just read it. Indeed, =
is more useful for two-way data binding but you might not need it.
Upvotes: 25