Watch controller model value from inside directive
Solution 1
$watch
accepts the "name" of the property to watch in the scope, you're asking it to watch the value. Change it to watch attrs.ngModel
which returns "bar", now you're watching scope.bar
. You can get the value the same way you were or use scope[attrs.ngModel]
which is like saying scope["bar"]
which again, is the same as scope.bar
.
scope.$watch(attrs.ngModel, function(newValue) {
console.log("Changed to " + newValue);
});
To clarify user271996's comment: scope.$eval
is used because you may pass object notation into the ng-model
attribute. i.e. ng-model="someObj.someProperty"
which won't work because scope["someObj.someProperty"]
is not valid. scope.$eval
is used to evaluate that string into an actual object so that scope["someObj.someProperty"]
becomes scope.someObj.someProperty
.
Solution 2
Wanted to add: in 1.2.x, with isolated scope, the above wont work. http://jsfiddle.net/TfTr5/23/
A workaround I came up with was using the fact that $watch also accepts a function, so you can access your controller using that.
scope.$watch(
function(){return controller.$viewValue},
function(newVal, oldVal){
//code
}
)
Working fiddle: http://jsfiddle.net/TfTr5/24/
If anyone has an alternative, I would gladly welcome it!
Solution 3
If you want to bind a value inside isolated scope,there are 2 ways to do it.The first way you can use even you don't have isolated scope.Here are the ways:
1) use $attrs.any_attribute
and bind it (set in watch)
2) use 2 ways binding ('=') method and set it into listener
if you want more with examples here is a great article
Related videos on Youtube
Dustin
Updated on March 03, 2020Comments
-
Dustin over 4 years
I am trying to have angular watch the
$viewValue
of a controller from inside a directive.fiddle: http://jsfiddle.net/dkrotts/TfTr5/5/
function foo($scope, $timeout) { $scope.bar = "Lorem ipsum"; $timeout(function() { $scope.bar = "Dolor sit amet"; }, 2000); } myApp.directive('myDirective', function() { return { restrict: 'A', require: '?ngModel', link: function (scope, element, attrs, controller) { scope.$watch(controller.$viewValue, function() { console.log("Changed to " + controller.$viewValue); }); } } });
As is, the $watch function is not catching the model change done after 2 seconds from inside the controller. What am I missing?
-
Jonathan Rowny over 11 yearsWorking fiddle since SO no longer likes fiddles in the answer: jsfiddle.net/TfTr5/7
-
Mark Rajcok over 11 yearsI think as long as you include a code sample somewhere in your answer SO will allow the fiddle link.
-
honzajde about 11 yearsok, except that there should be console.log("Changed to " + scope.$eval(attrs.ngModel));
-
sawe over 10 yearsscope.$watch(attrs.ngModel, function(newValue) { console.log("Changed to " + newValue); });
-
Jonathan Rowny over 10 yearsIf the scope is isolated then you can't go watching things in the parent scope. This is just as hacky but I think a little clearer to understand: jsfiddle.net/TfTr5/25 basically just do the watch on the parent scope. If you require ngModel, and your scope is isolated, it should be safe.
link: function (scope, element, attrs, controller) { scope.$parent.$watch(attrs.ngModel, function() { console.log("Changed to " + scope.$parent[attrs.ngModel]); }); }
but in general i wouldn't isolate something that needs to watch $parent scope. -
Jonathan Rowny over 10 yearsHa, yea that is simpler isn't it? I must have just been thinking based on the original question's example.
-
wlingke over 10 yearsI totally agree with you Johnathan. Your solution also works but correct me if I'm wrong, $viewValue isnt necessarily the same as the model value right? see here: jsfiddle.net/TfTr5/27 I believe if you are using angular's form validation, it doesn't update ngModel unless the $viewValue passes the validator. By the way, here's another solution that watches ngModel - but not $viewValue - that is a bit cleaner jsfiddle.net/TfTr5/26
-
Jonathan Rowny over 10 yearsYea, I forgot the original question was about the viewValue and if the scope is isolated then you can bi-diretionally bind ngModel which on the scope so your latest fiddle is good.
-
tanguy_k over 10 years@JonathanRowny please add an answer instead of commenting :)
-
Rafael Herscovici about 5 yearshow is debounce related?