I have made a user-name
directive for this question
.directive('userName', function($http) {
return {
restrict: 'E',
scope: {
user: '='
},
replace: true,
template: '<div><span ng-bind="user.username"></span> <a ng-if="user.active">Add</a></div>',
};
});
It is important that the directive uses a minimal number of watches when I use one-time binding af the user attribute (<user-name user="::user"></user-name>
).
I have a number of questions. I have created this plunker to test my directive.
- Why is there watchers in the one-time-binding case even though
user
will not update?
- Can I get down to zero watchers in this directive when using one-time binding?
- I have read in the documentation that I need a $watch in a link function to update the DOM - this doesn't seem to be the case for me. When is $watch necessary in the link function?
getWatchers
function doesn't provide meaningful feedback on watchers (summing up the watchers from scopes doesn't make much sense also). You can try $$postDigest
instead to monitor this kind of things.
Anyway, logging the scope from the directive after it was linked will give better feedback instantly.
As it shows, there are three watchers:
{isolateScope: Array[2], scope: Array[1]}
Two of them are user.username
and user.active
:
<div><span ng-bind="user.username"></span> <a ng-if="user.active">Add</a></div>
And the last one is {{$index}}
:
<li ng-repeat="user in users" id="user_a_{{$index}}">
Make them all one-time, and there should be zero.
When is $watch necessary in the link function?
Exactly as it was said, when something in the DOM that doesn't have data binding has to be updated when watched scope property is updated.
$watch gives a good amount of control when compared to bindings, e.g. the recipe for one-time watcher is
var unwatch = scope.$watch('oneTime', function (newVal, oldVal) {
unwatch();
...
});
And it can be changed to something like 'stop watching as soon as the variable is defined'.
It can also be used for watching the stuff outside the scope
scope.$watch(function () { return globalVar }, function () { scope.scopeVar = ... });