7

我有一个问题,最近出现的案例不止一个,我想知道解决这个问题的最佳方法。简单地说:

我有数据显示在 ng-repeat 中,按特定项目排序。例如,假设它按名称排序。我的目标是在按字母顺序排列的列表中的字母中断处设置标题:

----A----
Abe Lincoln
Adam Smith
----B----
Barack Obama
Barry Zuckercorn
----C----
...

等等。

我尝试过的事情包括:

  • 让控制器在模型数据进入时完全重建模型数据,手动将其放入一组字母组中。例如,我的服务有一个“帖子”数组,而我的控制器在服务更新时,手动将这些“帖子”打乱到一个“字母组”数组中。然后可能只有两个嵌套的 ng-repeats

但是,这依赖于对数据的大量操作,并且动态更改数据的排序方式并不容易。

  • 当模型更新时,让控制器通过手动单步执行数据来“添加”数据,检查字母何时更改,并在该元素上搭载“标题”属性(post.header = true)。然后 ng-repeat 可以检查它当前所在的元素是否是标题,并使用 ng-if 将其他内容插入 DOM。

这感觉稍微干净一些,但由于 ng-repeat 的工作方式,标题元素必须与 ng-repeating 元素处于同一级别“包含”。例如,如果您对<tr>元素执行 ng-repeat,这意味着不可能为标题插入另一个元素,<tr>因为特殊元素必须出现<tr>

最后,与上述相同:

  • 让控制器维护一个“关键索引”列表——这样做的好处是不会像上面的第二种方法那样修改数据,但通常以相同的方式工作。

编辑:

我在这里写了一篇博文,解释了我最终是如何处理这个问题的——感谢下面 Ian 的回答链接的 Google Groups 讨论。

4

2 回答 2

5

创建一个角度过滤器。它可以接受排序后的列表,按第一个字母对其进行分块,并为每个带有该字母的块返回一个对象,以及一个以该字母开头的对象数组。

例如,请参见此处的按大小筛选的块。请特别注意有关为分块值创建哈希值的讨论。

于 2013-07-03T08:12:04.967 回答
1

我编写了一个小指令来监视对象并自动将 $header 属性添加到列表中的第一个属性。像这样使用它:

 <div ng-repeat="item in data.items | orderBy:... | filter:... as filteredItems" header-list objects="filteredItems" header="getHeader">
    <div ng-show="item.$header">{{item.$header}}</div>
    <div>Your normal content</div>
 </div>

您可以根据需要传递一个构建标题的函数。该函数可以是您范围内的实例方法或函数。要获取第一个字母,请在您的控制器中定义。

$scope.getHeader = function(item) {
  return item.name.slice(0, 1);
}, 

该列表将在过滤器和订单更改时自动更新。

app.module("...").directive('headerList', function () {
  return {
    restrict: 'A',
    scope: {
      objects: '=',
      header: '=' // This must be a function or instance method
    },
    link: function(scope) {
      scope.$watch('objects', function() {

        var lastHeader, currentHeader;

        scope.objects.forEach(function (obj) {
          // We pass obj twice, so it can be used is instance method or regular function that takes the object as argument.
          currentHeader = scope.header.call(obj, obj);

          // in order to display a header per type, we mark the first event of each kind as header
          if (currentHeader !== lastHeader) {
            obj.$header = currentHeader;
            lastHeader = currentHeader;
          } else {
            obj.$header = null;
          }
        });

      });
    }
  }
});
于 2016-01-29T14:45:03.460 回答