Reputation: 7370
I want to use an AngularJS directive as HTML element, and provide it with two values: One is retrieved by iterating through a collection, and the other one is calculated from that value:
<mydirective myval="val" mymagic="getMagic(val)" ng-repeat="val in values" />
It works as expected when the getMagic(val)
function always returns the same value. In my case the result values are Arrays, and as each call results in a new value, I will end up in a
[$rootScope:infdig] 10 $digest() iterations reached. Aborting!
error. You can find a fiddle with my example here (if the function is defined like it is done in the commented line, it works).
Is there any way to not reevaluate or "watch" the mymagic parameter? I do want the value to be recalculated when the values collection changes, but the function should not be called apart from that.
Is there any way to achieve this?
Upvotes: 0
Views: 136
Reputation: 9616
Try this
(UPDATED JSFIDDLE)
http://jsfiddle.net/yogeshgadge/6T8mr/6/
notice the change - your getMagic() got called multiple times as the values returned also triggered the change and cause inifinite....10 digest
app.directive("mydirective", function () {
return {
restrict: "E",
transclude: false,
scope: {
myval: "=",
mymagic: "&" //passing the function
},
template: "<li>{{myval}} -- {{mymagic()}}</li>",
///mymagic() executing this function here
replace: true
};
});
Upvotes: 1
Reputation: 28757
I think you are concerned that getMagic(val)
is being called multiple times when the page is being rendered. What's going on is that the $digest cycle is running a few times to get the page completely rendered. This is expected behavior. See more information in the Angular guide to scopes.
What you can do is generate the magic numbers in the controller and attach it to a scope. And then any time the array or magic numbers change, you explicitly call $scope.$apply()
.
Something like this might work:
app.controller('Controller',
function ($scope) {
var getMagic = function(val){
return val + 1;
};
$scope.values = [3,7,1,2, 100];
$scope.magic = recalculate();
// EDIT: every time $scope.values changes, recalculate $scope.magic:
function recalculate() {
return $scope.values.map(getMagic);
}
$scope.$on('somthing-changed', recalculate();
});
Now, you will still need to ensure that every time either the values
or the magic
arrays change, you explicitly call $digest()
. This is not as elegant as using a $watch()
expression, but it will be more performant since you are not reevaluating the magic array more often than you need to.
Upvotes: 1