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?
You just create a myVar variable in your controller and pass it to the directive using my-var attribute. Since you are using two way binding, any changes made to myVar by the directive are available in your controller.
Using attrs you are able to access the attributes defined in your html tag like <fm-rating ng-model="$parent.restaurant.price" symbol="$" readonly="true"> So in this case you will have access to the symbol and readonly attributes.
Note: When you create a directive, it is restricted to attribute and elements only by default. In order to create directives that are triggered by class name, you need to use the restrict option. The restrict option is typically set to: 'A' - only matches attribute name. 'E' - only matches element name.
$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
.
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!
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