Reputation: 25565
I'm trying to create a custom directive that provides similar change notification as the input
control. With input controls, you can do the following:
<input type="text" ng-model="foo" ng-change="bar(a,b)">
In this case, the bar
function specified with ng-change
will only be called once every time the value of foo
is changed. I created a custom directive and I want to add the same type of change notification.
<div my-directive ng-model="foo" ng-change="bar(a,b)"></div>
I first tried to include the change handler in the scope and then execute it, but including it in the scope causes it to be called 12 times when it is instantiated and 12 times when it changes because I believe that is how often the attribute is being evaluated.
return {
templateUrl: '...',
restrict: 'A',
require: '^ngModel',
scope: {
ngModel: '=',
ngChange: '='
},
link: function postLink(scope, element, attrs) {
if(angular.isFunction(scope.ngChange) {
scope.ngChange(); // bar is called 12 times
}
}
}
Then I looked at the Angular source code and saw that they eval the value of the attribute for the change handler on input
. I tried to do that, but the specified function never seems to get called.
return {
templateUrl: '...',
restrict: 'A',
require: '^ngModel',
scope: {
ngModel: '='
},
link: function postLink(scope, element, attrs) {
scope.$eval(attrs.ngChange); // bar is never called
}
}
What would be the right way to do this?
Upvotes: 0
Views: 1393
Reputation: 1273
Use the next
return {
templateUrl: '...',
restrict: 'A',
require: '^ngModel',
scope: {
ngModel: '=',
ngChange: '&'
},
link: function postLink(scope, element, attrs)
{
scope.changingModel = function(newValue)
{
scope.ngModel = newValue;
scope.ngChange();
}
}
}
'&' is used to bind expressions. This will get your ngChange executed.
Using watchers is expensive. A watcher implies that angular will be checking for changes in your variable many, many times. If your variable is an array, it is worse, you must be very careful on the way you update your variable and be sure not to update your variable making changes on it but updating the whole thing at the same time. Something like:
var newValue = getMyNewValue($scope.foo);
$scope.foo = newValue;
The 'link' function is executed before any binding. Be aware of that.
I have been having a slight different problem that I assume you will face and that I hope someone else could solve for both of us.
In my case, I'm ussing something like
<div my-directive ng-model="foo" ng-change="bar(foo)"></div>
The execution of ngChange() will occur in the parent scope, that is in the scope where your bar function is defined. That is the expected behavior. But will be executed as if your model hasn't changed in your parent scope. I mean, bar(foo) will be executed with the old value of foo instead of the newValue.
Upvotes: 0
Reputation: 3822
If you want to call ngChange
every time that your model has been changed you can watch your model and call ngChange
in your watch callback.
Upvotes: 1