A function called multiple times from a template
In my template, I have something like this:
{{formatMyDate(date)}}
but date
- this is a scope variable that is not immediately available, so this expression will call the function formatMyDate()
multiple times (returning undefined
) before returning the correct value.
I could check if it is not date
invalidated in the function, but I think it would be cleaner NOT to call the function at all if date
- null
.
Any way to achieve this? Can a custom filter help me here?
EDIT:
It has been suggested that this behavior may be normal, depending on the $ digest cycle.
Then I put scope.$watch
to check how many times the value changes date
.
Note that I am defining them in a directive.
scope.$watch('date', function(value){
console.log('watched_date: ' + value)
})
and I also added console.log () to my function formatMyDate
scope.formatMyDate = function(date){
console.log("called_date: " + date)
return dateService.format(date, 'YYYY-MM-DD')
}
Console check I am getting (pseudocode)
called_date: undefined
watched_date: undefined
called_date: undefined // many many times (around 20/30)
called_date: correctValue //2 or 3 times
watched_date: correctValue
called_date: correctValue //other 3/4 times
I am wondering if this is still loop related $digest
or if this is a bug in my code
source to share
I would recommend that you do something differently:
Use a date$filter
or if you are doing something VERY unique and the date is $filter
not enough for you, then you can create your own $filter
, for example:
app.filter('formatMyDate', function () {
return function (date) {
if (!date) return "";
var result;
//your code here
return result;
};
});
And use it like in your template:
{{date | formatMyDate}}
UPDATE:
I guess I didn't quite answer your question, I just gave you advice on how to improve the code. This time I'll try to answer your question:
The $ digest loop is where Angular ensures that the model settings are changed so that it can render the view with the updated changes. To do this, Angular runs a loop in which each iteration evaluates all the expressions in the view template as well as the function's $watcher
functions $scope
. If in the current iteration the result is the same as the previous one, then Angular will exit the loop. Otherwise, it will try again. If after 10 attempts everything is not settled, Angular will exit with an error: "Infite $ digest Loop Error" (infdig) .
So, the first time the loop $digest
is executed, all expressions are evaluated (at least) twice. And then every time you make changes to $scope
, or one $watcher
of the $scope
runs, the cycle $digest
starts again, to make sure that everything is settled, so your expression will be evaluated again. This is how Angular does "data binding", this is normal behavior.
So in your case, when in your template you do this: {{formatMyDate(date)}}
or this one {{date | formatMyDate}}
, you define Angular expressions that will be evaluated every time the loop is $digest
run, which, as you can imagine, very often. Therefore, it is very important to make sure that $filters
(or the functions) you use in your view are efficient and inactive.
source to share
You can do it:
{{date && formatMyDate(date)}}
will only execute the second case if the first condition exists and is nonzero and undefined.
Check out this fiddle: http://jsfiddle.net/HB7LU/7512/
source to share