$watch ngModel from inside directive using isolate scope
JavascriptAngularjsAngularjs DirectiveJavascript Problem Overview
I am trying to watch my model value from inside my linking function.
scope.$watch(attrs.ngModel, function() {
console.log("Changed");
});
When I change the model value inside my controller, the $watch function is not triggered.
$scope.myModel = "ACT";
$timeout(function() {
$scope.myModel = "TOTALS";
}, 2000);
Fiddle: http://jsfiddle.net/dkrotts/BtrZH/4/
What am I missing here?
Javascript Solutions
Solution 1 - Javascript
You'll need to watch a function that returns the $modelValue you're watching.
The following code shows a basic example:
app.directive('myDirective', function (){
return {
require: 'ngModel',
link: function(scope, element, attrs, ngModel) {
scope.$watch(function () {
return ngModel.$modelValue;
}, function(newValue) {
console.log(newValue);
});
}
};
});
Here's a plunker of the same idea in action.
Solution 2 - Javascript
The problem is that you $watch
ing attrs.ngModel
which is equal to "myModel". You do not have "myModel" bound in your scope. You want to $watch
"model". That is what is bound in the scope of your directive. See http://jsfiddle.net/BtrZH/5/
Solution 3 - Javascript
The proper way to do this is:
app.directive('myDirective', function () {
return {
require: 'ngModel',
link: function (scope, element, attrs, ngModel) {
ngModel.$render = function () {
var newValue = ngModel.$viewValue;
console.log(newValue)
};
}
};
});
Solution 4 - Javascript
Here is another way to do this:
app.directive('myDirective', function (){
return {
require: 'ngModel',
link: function(scope, element, attrs, ngModel) {
attrs.$observe('ngModel', function(value){ // Got ng-model bind path here
scope.$watch(value,function(newValue){ // Watch given path for changes
console.log(newValue);
});
});
}
};
});
Doing it that way you will be able to listen value changes with binds like that
Solution 5 - Javascript
This is an extension of @ Emmanuel's answer above to answer @Martin Velez, although I know it's pretty late! (Also I can't make comments yet, so if this isn't the right place for this, sorry!)
I'm not sure which version of Angular OP was using, but in Angular#1.2+ at least on the official docs https://docs.angularjs.org/api/ng/type/ngModel.NgModelController#$render, $render is listed like this:
> Called when the view needs to be updated. It is expected that the user > of the ng-model directive will implement this method. > > The $render() method is invoked in the following situations: > > $rollbackViewValue() is called. If we are rolling back the view value > to the last committed value then $render() is called to update the > input control. The value referenced by ng-model is changed > programmatically and both the $modelValue and the $viewValue are > different from last time. Since ng-model does not do a deep watch, > $render() is only invoked if the values of $modelValue and $viewValue > are actually different from their previous value.
I interpret this to mean that the correct way to $watch an ngModel from a directive is to require ngModel and implement a link function that injects ngModelController. Then use the ngModel API that's built in to $render-on-change ($watch), or whatever else.
Solution 6 - Javascript
There are 2 ways to do it.
-
You can use
$attrs.[any_attribute]
and set on it any listener -
You can have isolated scope with 2 ways binding variable and set a listener on it.If you want more,here is a cool article