AngularJS”;标题“;在ng重复中

AngularJS "headers" in ng-repeat

本文关键字:ng 标题 AngularJS      更新时间:2023-09-26

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

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

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

等等

我尝试过的东西包括:

  • 让控制器在模型数据进入时完全重新构建模型数据,手动将其放入字母组数组中。例如,我的服务有一个"帖子"数组,当服务更新时,我的控制器会手动将这些"帖子"打乱为一个"letterGroups"数组。那么就有可能只有两个嵌套的ng重复

然而,这依赖于对数据的大量操作,并且不容易随时更改数据的排序方式。

  • 当模型更新时,让控制器通过手动遍历数据、检查字母何时更改以及在该元素(post.header = true)上搭载"header"属性来"掺杂"数据。然后ng repeat可以检查它当前所在的元素是否是头,并使用ng if将其他内容插入DOM

这感觉稍微干净一些,但由于ng重复的工作方式,标头元素必须与ng重复元素"包含"在同一级别。例如,如果在<tr>元素上执行ng repeat,则意味着不可能为标头插入另一个<tr>,因为特殊元素必须出现在<tr> 内部

最后,沿着与上面相同的路线:

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

编辑:

我在这里写了一篇博客文章,解释了我最终是如何处理这个问题的——这要归功于下面伊恩的回答所链接的谷歌小组讨论。

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

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

我编写了一个小指令,用于监视对象并自动将$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;
          }
        });
      });
    }
  }
});