AngularJS: Can I use a filter to chunk an array in ng-repeat?

前端 未结 3 1180
失恋的感觉
失恋的感觉 2021-01-21 01:14

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

相关标签:
3条回答
  • 2021-01-21 01:35

    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.

    0 讨论(0)
  • 2021-01-21 01:44

    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!

    0 讨论(0)
  • 2021-01-21 01:48

    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);
      });
    
    0 讨论(0)
提交回复
热议问题