iterate over chunks of an array using ng-repeat

All we need is an easy explanation of the problem, so here it is.

My controller grabs people from the server:

$scope.people = [person1, person2, person3, person4, person5,...]

My template needs to display three people per line. For example if it was a table:

<table>
    <tr>
        <td>person1</td><td>person2</td><td>person3</td>
    </tr>
    <tr>
        <td>person4</td><td>person5</td><td>person6</td>
    </tr>
</table>

I wasn’t sure how to conditionally apply the <tr> when $index % 3 == 0 or what the best practices are. I know how to do this by adding grouping logic to the controller but I thought it would be best to keep design logic out of the controller.

How to solve :

I know you bored from this bug, So we are here to help you! Take a deep breath and look at the explanation of your problem. We have many solutions to this problem, But we recommend you to use the first method because it is tested & true method that will 100% work for you.

Method 1

There isn’t an existing way to do what you are saying with a table. The easiest way to do what you want is to use divs with fixed widths, so that they will auto-wrap after three.

Here is an example:

HTML

<div ng-app="app">
    <div ng-controller="TableCtrl" class="my-table">
        <span ng-repeat="person in people" class="person">{{person}}</span>
    </div>
</div>

CSS

.my-table{
    width: 400px;
    height: 400px;
    border: 1px solid black;
}

.person{
    width: 100px;
    display: inline-block;
    white-space: nowrap;
    border: 1px solid black;
}

JavaScript

var app = angular.module('app',[]);
app.controller('TableCtrl', function($scope){

    $scope.people = ['Aaron', 'Abraham', 'Adam', 'Aristotel', 'Aziel', 'Azod', 'Azood'];

});

Working copy: http://jsfiddle.net/ZX43D/

Method 2

After years of angular experience, It’s obvious that the best way to do this is to split the array into chunks in the controller. Each time the original array is modified, update the chunked array.

Method 3

Here is my current solution (It’s O(N^2) so doesn’t scale for large lists).

Template:

<div ng-app="myapp">
    <div ng-controller="testing">
        <div ng-repeat="_ in items">
            <span ng-show="($parent.$index % 3 == 0) && ($parent.$index + 3 > $index) && ($parent.$index <= $index)" ng-repeat="item in items">
                <span ng-show="1">
                    {{item}}
                </span>
            </span>
        </div>
    </div>
</div>

Controller:

angular.module('myapp', []);

function testing($scope){
    $scope.items = ['a', 'b', 'c', 'd','e','f','g'];
}

Result:

a b c
d e f
g

Fiddle:

http://jsfiddle.net/LjX3m/

Conclusion:

I’ll probably try use CSS for this as @aaronfrost mentions. (However it may not be possible since some wrapping divs may be required for each chunk).

Note: Use and implement method 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply