I'm running into an issue where I want to bind to the output of a function inside of an ng-repeat loop. I'm finding that the function is being called twice per item rather than once as I'd expect. Here's the ng-repeat section (notice the calcRowTotal() call at the end):
<tr ng-repeat="row in timesheetRows">
<td>
<select ng-model="row.categoryID">
<option ng-repeat="category in categories" value="{{category.id}}">
{{category.title}}
</option>
</select>
</td>
<td ng-repeat="day in row.dayValues">
<input type="text" ng-model="day.hours" />
</td>
<td>{{calcRowTotal($index, row)}}</td>
</tr>
The calcRowTotal() function is shown next:
$scope.calcRowTotal = function (index, row) {
console.log('calcRowTotal - Index: ' + index);
var total = 0;
for (var i = 0; i < row.dayValues.length; i++) {
var num = parseFloat(row.dayValues[i].hours);
if (isNaN(num)) {
num = 0;
//this.dayValues[i].hours = 0;
}
total += num;
}
//updateDayTotals();
return total;
}
An example of one of the items being iterated through is shown next:
{
categoryID: 2,
dayValues: [
{ day: $scope.days[0], hours: 5 },
{ day: $scope.days[1], hours: 0 },
{ day: $scope.days[2], hours: 3 },
{ day: $scope.days[3], hours: 0 },
{ day: $scope.days[4], hours: 2 },
{ day: $scope.days[5], hours: 5 },
{ day: $scope.days[6], hours: 8 }
]
}
I'm seeing the following in the console (two items are currently in the collection I'm looping through):
calcRowTotal - Index: 0
calcRowTotal - Index: 1
calcRowTotal - Index: 0
calcRowTotal - Index: 1
I could certainly make a "rowTotal" property but would prefer to bind to "live" data provided by the function shown above. Hopefully the duplication is something simple I'm missing so I appreciate any feedback on why I'm seeing the duplication. As a side note, as data in one of the textboxes changes I need to update the row totals as well so it may be I need a different approach. Interested in understanding this particular situation first though....definitely don't want the duplication because there could be a lot of rows potentially.
Here's an example: http://jsfiddle.net/dwahlin/Y7XbY/2/
- GeeksforGeeks How to call a function repeatedly every 5 seconds in JavaScript ? The setInterval () method in JavaScript can be used to perform periodic evaluation of expression or call a JavaScript function. setInterval (function, milliseconds, param1, param2, ...) function: This parameter holds the function name which to be called periodically.
When Angular’s digest cycle runs, every watcher is asked to update its state. In the case of ng-class, it will re-run the function bound to it, to see if anything needs to change. This is why your controller function runs multiple times, and it’ll run again each time something changes on the page.
The ng-repeat directive repeats a set of HTML, a given number of times. The set of HTML will be repeated once per item in a collection. The collection must be an array or an object.
When the digest cycle runs, it effectively redraws everything that might have changed on the page. Angular uses some tricks to find “everything that might have changed”, and the main technique is watchers. These watchers are created automatically when you use directives like ng-if and ng-class, and when you use bindings like { { yourBindingHere }}.
It's because you're binding to a function expression here:
<td>{{calcRowTotal($index, row)}}</td>
What that does it force that function to be reevaluated on every item, on every digest. What you'll want to do to prevent that is pre-calculate that value and put it in your array to begin with.
One way to do that is to set up a watch on your array:
$scope.$watch('timesheetRows', function(rows) {
for(var i = 0; i < value.length; i++) {
var row = rows[i];
row.rowTotal = $scope.calcRowTotal(row, i);
}
}, true);
Then all you have to do is bind to that new value:
<td>{{row.rowTotal}}</td>
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