3

I have a simple ng-repeat going on:

<div class="row-fluid">
  <div class="span4" ng-repeat="piece in clothes | filter:query">
    <img ng-src="{{piece.mainImage[0]}}" class="thumbImg" />
    <a href="#/json/{{piece.systemName}}">{{piece.name}}</a>
  </div>
</div>

After 3 repeats, I'd like to stop the repeat, add in a closing <div> and open a new .row-fluid (to start a new line), then re-start the loop where I left off, inserting the tags each 3rd time.

The docs for Angular are really hard to traverse, making it difficult to work out how to do this.

JVG
  • 20,198
  • 47
  • 132
  • 210
  • possible duplicate of [Angular.js using bootstrap and dynamically creating rows](http://stackoverflow.com/questions/14748449/angular-js-using-bootstrap-and-dynamically-creating-rows) – lucuma May 12 '13 at 14:44

2 Answers2

8

You could create a filter for array partitioning. (If you can use some library, you may be able to get something shorter & more efficient.)

app.filter('partition', function() {
  var part = function(arr, size) {
    if ( 0 === arr.length ) return [];
    return [ arr.slice( 0, size ) ].concat( part( arr.slice( size ), size) );
  };
  return part;
});

You can use it like:

<div  ng-repeat="rows in list | partition:3">
  <div class="row" ng-repeat="item in rows">
    <div class="span4">{{ item }}</div>
  </div>
</div>
Tosh
  • 35,955
  • 11
  • 65
  • 55
  • Nice and clean! I'm starting to reconsider my fear of filters in Angular... ;) – Supr May 13 '13 at 03:43
  • 6
    Using this exact code is giving me an infinite $digest loop. Strange. http://jsbin.com/UmOMAgA/8/edit – m59 Sep 03 '13 at 04:54
  • This solutions works: http://stackoverflow.com/questions/21644493/how-to-split-the-ng-repeat-data-with-three-columns-using-bootstrap – Cornelius Schmale Dec 10 '14 at 15:11
5

ngRepeat will keep re-evaluating the filter infinitely because it gets different values every time it's ran.

This terrible code seems to work in the general case. If you have identical arrays things could get hairy. We need to be able to compare arrays for equality, but that's a difficult problem. I took the easy/flimsy way out and just used stringify(). Could not get angular.equals() to work for me; I think it probably just works on shallow objects.

app.filter('partition', function($cacheFactory) {
  var arrayCache = $cacheFactory('partition')
  return function(arr, size) {
    var parts = [], cachedParts,
      jsonArr = JSON.stringify(arr);
    for (var i=0; i < arr.length; i += size) {
        parts.push(arr.slice(i, i + size));        
    }
    cachedParts = arrayCache.get(jsonArr); 
    if (JSON.stringify(cachedParts) === JSON.stringify(parts)) {
      return cachedParts;
    }
    arrayCache.put(jsonArr, parts);

    return parts;
  }; 
});
boneskull
  • 1,189
  • 12
  • 11
  • 1
    Win answer. Just win. – m59 Sep 03 '13 at 08:39
  • Here's a jsbin where I ran the code through the ringer looking for any unforseen bugs. http://jsbin.com/UmOMAgA/19/edit With the changes we discussed (identify by size on cache get/put) I can't find any circumstance that this will fail. Again, great job! – m59 Sep 03 '13 at 08:58