Reputation: 65
I wrote a controller containing this function:
$scope.getItemName = function (id) {
sgcdata.get('item', {
_id: id
}).then(function (dataItem) {
return dataItem[0].brand_name + " " + dataItem[0].reference;
});
}
And in the view:
<li ng-repeat="itemCart in connectedUser.cart track by $index" class="list-group-item">
<span class="badge cursorpointer" ng-click="removeFromCart(itemCart)">X</span>
<a href="#">{{ getItemName(itemCart) }}</a>
</li>
When I do this, I get an infinite loop ($rootScope:infdig
).
sgcdata.get
make an XHR request.
But if I return a simple string, it works:
$scope.getItemName = function (id) {
return "toto";
}
I really don't understand what is happening...
Thanks for your help.
Edit
I made a filter instead of the previous function:
JS:
sgc.filter('getItemName', [
'sgcdata',
function (sgcdata) {
return function (id) {
sgcdata.get('item', {
_id: id
}).then(function (dataItem) {
return dataItem[0].brand_name + " " + dataItem[0].reference;
});
}
}
]);
HTML:
<li ng-repeat="itemCart in connectedUser.cart track by $index" class="list-group-item">
<span class="badge cursorpointer" ng-click="removeFromCart(itemCart)">X</span>
<a href="#">{{ itemCart | getItemName }}</a>
</li>
I don't have any infinite loop anymore, but I can't get several values in the ng-repeat, while the filter return is in the item request.
Edit
sgcdata.get:
service.get = function (collection, filters) {
var deferred = $q.defer();
var formatRequest = function (obj) {
var str = [];
for (var p in obj) {
str.push(encodeURIComponent(p) + '=' + encodeURIComponent(obj[p]));
}
if (str.length) {
return '&' + str.join('&');
} else {
return '';
}
};
$http({
method: 'GET',
url: '/v1/get/?element=' + collection.toLowerCase() + formatRequest(filters)
}).then(function (response) {
deferred.resolve(response.data);
}, function (response) {
console.error("[ FAILED ] >> " + response);
});
return deferred.promise;
}
Upvotes: 0
Views: 537
Reputation: 22323
Calling a function from within an ng-repeat
HTML Template will always cause an Infinite Digest
error, because of the nature of the Digest cycle itself.
Essentially, the ng-repeat
attempts to render the child nodes. In the child nodes, you are calling a function, which causes a Digest to occur. This new Digest causes the ng-repeat
to start over, which causes the child nodes to be run again, which causes another Digest, ad infinitum.
There are a few generally accepted ways to deal with this, each with their own pros and cons.
When fetching the original array from the server, do the logic on the server to include all the relevant fields in the original return value. This is ultra efficient, because you allow your server to do all the heavy lifting, and there is only a single call to the server. However, you may be sending extra data that is only useful to a small portion of your app, and this could slow down initial startup times.
When fetching the original array, run the function for each element returned to add the extra data as a new property on each element. This is fairly efficient, because it means all your data is front loaded, and you only have to make a single extra call per element. This can suffer from the same negative that you are sending not commonly used data, and this can also amplify the initial startup slowdown if you have many elements to iterate through.
Add a filter to the ng-repeat
, rather than the elements, which iterates through the array and fetches the extra data exclusively for the ng-repeat
. This has the advantage of only making the extra calls to the server when the ng-repeat
is present, and this does not add the extra data to the original array. However, these extra calls to the server would be executed any time the ng-repeat
changes (new elements added, items deleted, other filter applied, etc.), which could incur a major performance penalty depending on the amount of data and the frequency of change.
Upvotes: 1
Reputation: 191058
You should return the same reference or value from the function. Otherwise things will spin out of control.
Upvotes: 1