【问题标题】:AngularJS: Can I use a filter to chunk an array in ng-repeat?AngularJS:我可以使用过滤器在 ng-repeat 中对数组进行分块吗?
【发布时间】:2020-09-07 21:40:18
【问题描述】:

编辑以添加一个明确的问题:我有一个一定长度的平面数组,我想将它放入 tr/td 类型的视图中?这也可能在引导网格或类似的东西中。本质上,我想在一系列长度为 n 的块中显示一个平面数组。

关于 SO,这个问题有很多变体,但我还没有真正看到任何一个很好的解释:如何使这项工作或为什么不能。所以我做了一个非常simple example 来证明这个问题。它会呈现,但如果您检查日志,您会看到错误(太大而无法链接到)。

index.html:

<!DOCTYPE html>
<html lang="en-US" ng-app="rowApp">
<head><title>Angular chunks</title>
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.9/angular.min.js" integrity="sha384-c4XWi4+MS7dBmCkPfB02+p/ExOF/ZBOfD2S4KR6mkmpBOg7IM6SUpA1KYZaVr7qE" crossorigin="anonymous"></script>
  <script src="app.js"></script>
</head>
<body>
  <table ng-controller="rowController" border="1" style="width:30%">
    <tr ng-repeat="people_chunk in people | chunk:4">
      <td ng-repeat="person in people_chunk">{{person.name}}</td>
    </td>
  </table>
</body>
</html>

app.js:

var rowApp = angular.module('rowApp', ['filters']);

angular.module('filters', []).
  filter('chunk', function () {
    return function (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;
    };
});

rowApp.controller('rowController',
  function ($scope, $http) {
    $http.get("/people.json")
      .then(function(response) { $scope.people = response.data; });
});

people.json:

[{"name": "a"}, {"name": "b"}, {"name": "c"}, {"name": "d"},
 {"name": "1"}, {"name": "2"}, {"name": "3"}, {"name": "4"}]

然后您可以使用python -m SimpleHTTPServer 9000 提供所有这些,然后转到http://localhost:9000/

【问题讨论】:

  • 你想把一个数组分成 4 份,然后用 ng-repeat 重复它们吗?
  • 真的不清楚你的目标是什么。
  • 您收到的错误消息可能是由于无限循环。您可以查看是否使用断点,您的过滤器会一直执行到 Angular 将其杀死。
  • @K.Gkinis 好的,这似乎是可能的。但我不清楚为什么。 (我在开头提出了一个明确的问题)
  • 我认为这是特定于演示的逻辑,应该使用 CSS 来完成

标签: javascript angularjs


【解决方案1】:

您可以通过简单地记住您的块函数来避免无限的摘要循环。这解决了 ng-repeat 永远找不到正确的引用并总是认为您正在返回导致无限 $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);
  });

【讨论】:

  • 有趣。我看到了一个类似的答案,但它假设你有 lodash 我还没有。用这个做了一个so-answer-2分支。一个问题:角度缓存可以在这里工作吗?
  • 它似乎没有将 chunk_size 正确传递给 chunk 方法。我认为缓存也是基于数组作为第一个参数,而不是设置属性名称的最佳方式。
  • 它可以工作,但由于全局范围的垃圾,将 cache = {}; 更改为 var cache = {}
【解决方案2】:

由于过滤器将新数组实例作为切片返回,Angular 的ngRepeat 将检测到它们已更改(因为ngRepeat 在内部使用$watchCollection),并将导致无限摘要循环。甚至还有一个问题,但自 2013 年以来就被放弃了:https://github.com/angular/angular.js/issues/2033

如果您将 sn-p 更改为包含非常量表达式(如 [[x]]),此问题仍然存在:

<div ng-repeat="a in [[x]]">
  <div ng-repeat="b in a">
  </div>
</div>

恐怕你将不得不将分块逻辑移动到控制器中,或者使用 css 来形成一个 4 宽度的表格。

【讨论】:

  • 啊。这就是为什么另一个类似的问题有一个“记忆”电话......好吧。谢谢。宁愿没有它在控制器中,但那是我最终把它放在哪里。现在至少我知道为什么它必须在那里。谢谢!
  • 您应该将分块逻辑移至服务恕我直言。 (但这是一个正确的答案:))
【解决方案3】:

也许这对某人有用,你永远不知道

以下代码将为商店数组分配一个额外的值(store_chunk)。所以我可以使用 ng-repeat 在我的 HTML 中显示 3 个不同的列

        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;
        });

这里是 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>

这就像一个魅力!并且不要仅仅因为你不喜欢它就投反对票!...竖起大拇指!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-03-12
    • 2014-03-06
    • 2019-06-16
    • 1970-01-01
    • 1970-01-01
    • 2018-01-28
    • 2019-10-07
    相关资源
    最近更新 更多