1

Let's say, I have an array of objects and I want to display it in several rows. Each row should consist of a specific number of objects. Basically, it should look like this:

<div class="row">
    <div class="col-md-4">item</div>
    <div class="col-md-4">item</div>
    <div class="col-md-4">item</div>
</div>
<div class="row">
    <div class="col-md-4">item</div>
    <div class="col-md-4">item</div>
    <div class="col-md-4">item</div>
</div>
...

I've implemented it with a very dirty trick, generating an additional array of numbers and iterating through it (4 is a number of objects in a row):

<div class="row titles-row" ng-repeat="row in outRange(series.length, 4)">
    <project-preview class="col-md-3" ng-repeat="project in series" ng-if="$index < (row + 1)*4&& $index >= (row)*4"></project-preview>
</div>

and outRange function:

$scope.outRange = function(items_num, row_width) {
    items_num = items_num > 0 ? items_num : 0;
    var rows_num = Math.ceil(items_num / row_width);
    return Array.apply(null, Array(rows_num)).map(function (_, i) {return i;});
};

It works, but I feel like there should be a better way to do it.

troorl
  • 1,579
  • 1
  • 15
  • 20

3 Answers3

2

If this is just a matter of presentation, bootstrap (which it seems you might be using) will automatically put the other objects on a separate row when the sum of columns is more than 12 (it uses floats). If however the objects have significantly different sizes, this might not look so good indeed. Still, I would tend to leave this under control of CSS, rather than in javascript.

One approach would be to use a display: flexbox on the container, which should have the effect you want automatically. Lookup this CSS property to discover the true strength of flexbox.

If you really want to do it in javascript, you could have a template like:

<div ng-class='{row: $index % 4 == 0}' ng-repeat='...'>
   <div class='col-md-4'>
          ..
   </div>
</div>

This will generate extra divs, but that is likely acceptable.

manuBriot
  • 2,755
  • 13
  • 21
1

Instead of outRange, use a filter to create chunks out of the series array. Lodash has a chunk method. Or you can implement one yourself.

Community
  • 1
  • 1
Anid Monsur
  • 4,538
  • 1
  • 17
  • 24
0

Thanks for your ideas. I came up with this solution:

mainApp.filter('slice', function() {
    return function(array, row_width, scope) {
        if(array == undefined)
            return;
        if(scope.sliceResult != undefined)
            return scope.sliceResult;

        scope.sliceResult = [];
        var rows_num = Math.ceil(array.length / row_width);
        for(var i = 0; i < rows_num; i++) {
            scope.sliceResult.push(array.slice(i * row_width, i * row_width + row_width));
        }

        return scope.sliceResult;
    };
});

And here how I use it:

<div class="row titles-row" ng-repeat="row in series | slice: 4 : this">
    <project-preview class="col-md-3" ng-repeat="project in row"></project-preview>
</div>

Still I don't like that I need to pass the scope inside the filter.

troorl
  • 1,579
  • 1
  • 15
  • 20