Reputation: 19967
I'm new to AngularJS and am running into a problem.
I have a JSON array of invoices retrieved via a $http GET request that is being looped through here:
<a ng-repeat="invoice in invoices" href="#" class="list-group-item">
{{ invoice[data]["TxnDate"][0] }} -
{{ invoice[data]["DocNumber"][0] }} -
${{ invoice[data]["TotalAmt"][0] }} -
{{ getCustomer(invoice[data]["Id"][0]) }}
<i class="fa fa-chevron-right pull-right"></i>
<i class="pull-right">Edit</i>
</a>
The problem is that the array of invoices does not store any information about the customer except for the customer's reference number.
So, I created a function called getCustomer
which queries my API for the customer's name by their reference number.
$scope.getCustomer = function(id) {
var customer_id = id.match(/\d+/)[0];
$http.post('/customers', customer_id).success(function(response) {
console.log(response);
});
};
The problem is I am receiving this error:
error: [$rootscope:infdig] 10 $digest() iterations reached. aborting! watchers fired in the last 5 iterations: []
Later, I will figure out a more efficient way to do this but I'm curious to know what is causing this error?
After doing some research, I think it has something to do with the fact that once the data in one of the list items changes, AngularJS needs to check all the list items. Still, I'm very confused. What is the right way of doing this?
Upvotes: 3
Views: 5809
Reputation: 4839
The problem is related to the use of a function inside a binding (interpolation {{}}). Due to its nature, angularjs constantly observes the $scope (view model) for changes. So if you are not careful you could bind to a function that always returns a new/different instance of an object. This triggers an infinite loop that angular identifies as an error and disables the binding in order to avoid stackoverflow. If say you changed your function to store the returned customer to a local variable you could avoid the problem.
Here is a complete snippet.
var app = angular.module('main', []);
app.controller('MainCtrl', function($scope, $http, $q) {
$scope.invoices = [
{ Id: "1", TxnDate: new Date(2014, 6, 26), DocNumber: "I001234", TotalAmt: 200.34 },
{ Id: "2", TxnDate: new Date(2014, 8, 2), DocNumber: "I000021", TotalAmt: 530.34 },
{ Id: "3", TxnDate: new Date(2014, 11, 15), DocNumber: "I000023", TotalAmt: 123 },
{ Id: "4", TxnDate: new Date(2014, 12, 11), DocNumber: "I000027", TotalAmt: 5000 },
];
var testUrl = 'http://echo.jsontest.com/company/AKME/firstName/John/lastName/Doe';
var _customerCache = {};
$scope.customerCache = _customerCache;
$scope.getCustomer = function(id) {
var deferred = $q.defer(); // defer
if (_customerCache[id])
return deferred.resolve(_customerCache[id]);
var customer_id = id.match(/\d+/)[0];
$http.get(testUrl + customer_id + '/id/'+ customer_id).success(function(response) {
console.log(response);
_customerCache[id] = response;
deferred.resolve(response);
});
return deferred.promise;
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="main" ng-controller="MainCtrl">
<ul>
<li ng-repeat="invoice in invoices" ng-init="getCustomer(invoice.Id)">
<a href="#" class="list-group-item">
{{ invoice.TxnDate | date }} -
{{ invoice.DocNumber }} -
{{ invoice.TotalAmt | currency }}
{{ customerCache[invoice.Id].firstName }} {{ customerCache[invoice.Id].lastName }}
</a>
</li>
</ul>
<span>customers via http</span>
<ul>
<li ng-repeat="cust in customerCache">
{{cust}}
</li>
</ul>
<div>
Upvotes: 6