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;
}
Calling a function from within an
ng-repeat
HTML Template will always cause anInfinite 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 theng-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 theng-repeat
. This has the advantage of only making the extra calls to the server when theng-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 theng-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.