Edit to add a clear question: I have a flat array of some length and I want to put it into a tr/td type view? This might also be in a bootstrap grid or somethin
As the filter is returning new array instances as slices, angular's ngRepeat
will detect them changed (as ngRepeat
uses $watchCollection
internally), and will cause and infinite digest loop. There is even an issue about that, but it is abandoned since 2013: https://github.com/angular/angular.js/issues/2033
This issue still persists if you change the snippet to contain a non-constant expression, like [[x]]
:
<div ng-repeat="a in [[x]]">
<div ng-repeat="b in a">
</div>
</div>
I am afraid you will have to move the chunking logic into the controller, or to use css to form a 4-width table.
maybe this could work to someone, you never know
the following code will assign an extra value (store_chunk) to an array of stores. so I can use with ng-repeat to show 3 different columns in my HTML
var x = 0;
var y = 1;
var how_many_chunks = 3;
var limit = $scope.main.stores.length / how_many_chunks ;
angular.forEach($scope.main.stores, function(e, key) {
if (x <= limit) {
$scope.main.stores[key].store_chunk = y;
}
else{
y += 1;
limit = y * limit;
$scope.main.stores[key].store_chunk = y;
}
x += 1;
});
here the HTML
<div class="row">
<div class="col-xs-12 col-sm-3 col-md-3 col-lg-3">
<ul class="main_report">
<li ng-repeat="store in main.stores | filter:{ store_chunk: 3 }">{{store.store_name}}</li>
</ul>
</div>
<div class="col-xs-12 col-sm-3 col-md-3 col-lg-3">
<ul class="main_report">
<li ng-repeat="store in main.stores | filter:{ store_chunk: 3 }">{{store.store_name}}</li>
</ul>
</div>
<div class="col-xs-12 col-sm-3 col-md-3 col-lg-3">
<ul class="main_report">
<li ng-repeat="store in main.stores | filter:{ store_chunk: 3 }">{{store.store_name}}</li>
</ul>
</div>
</div>
this works like a charm! and don't vote down just because you didn't like it!.. thumbs up instead!
You can avoid an infinite digest loop by simply memoizing your chunk function. This solves the issue of ng-repeat never finding the proper references and always thinking you are returning new items causing the infinite $digest.
angular.module('filters', []).
filter('chunk', function () {
function cacheIt(func) {
var cache = {};
return function(arg, chunk_size) {
// if the function has been called with the argument
// short circuit and use cached value, otherwise call the
// cached function with the argument and save it to the cache as well then return
return cache[arg] ? cache[arg] : cache[arg] = func(arg,chunk_size);
};
}
// unchanged from your example apart from we are no longer directly returning this
function chunk(items, chunk_size) {
var chunks = [];
if (angular.isArray(items)) {
if (isNaN(chunk_size))
chunk_size = 4;
for (var i = 0; i < items.length; i += chunk_size) {
chunks.push(items.slice(i, i + chunk_size));
}
} else {
console.log("items is not an array: " + angular.toJson(items));
}
return chunks;
}
// now we return the cached or memoized version of our chunk function
// if you want to use lodash this is really easy since there is already a chunk and memoize function all above code would be removed
// this return would simply be: return _.memoize(_.chunk);
return cacheIt(chunk);
});