在angularjs中显示聚合列表

时间:2013-01-04 18:48:10

标签: javascript angularjs

在我的模型中,我的数据类似于:

$scope.list = [{id:0,tags:['tag1','tag2']},{id:2,tags:['tag2']}};

我想用复选框显示标签列表(包含'tag1'和'tag2'的唯一值)。希望如下:

<div ng-repeat="tag in list.tags">
    <label class="checkbox">
        <input type="checkbox" ng-model="filter.tag" />
        {{tag}}
    </label>
</div>

我知道如何根据已检查的内容过滤主列表,如果我对列表进行硬编码,而不是如何自动生成唯一标记列表。

2 个答案:

答案 0 :(得分:26)

您正在寻求执行三项操作:

  • $scope.list
  • 中的每个项目中获取标记数组
  • 将这些展平为一个数组
  • 从此数组中获取唯一值

您可以使用纯JavaScript执行此操作,但为了简化操作,我建议使用Underscore,这是一个库,可让您访问许多用于操作和检查数组,对象等的函数。

让我们从这段代码开始:

$scope.list = [
  {id: 0, tags: ['tag1', 'tag2']},
  {id: 1, tags: ['tag2']},
  {id: 2, tags: ['tag1', 'tag3', 'tag4']},
  {id: 3, tags: ['tag3', 'tag4']}
];

现在,让我们执行第一个操作:从tags中的每个对象的$scope.list属性中获取数组。 Underscore提供了pluck方法,这正是我们所需要的。

  

采摘 _.pluck(list, propertyName)

     

可能是map最常见的用例的便捷版本:提取属性值列表。

使用pluck,我们可以得到以下结果:

var tags = _.pluck($scope.list, 'tags');
// gives us [['tag1', 'tag2'], ['tag2'], ['tag1', 'tag3', 'tag4'], ['tag3', 'tag4']]

现在,我们想要展平该数组。

  

展平 _.flatten(array, [shallow])

     

展平嵌套数组(嵌套可以是任何深度)。如果你传递浅,那么数组只会被压平一个级别。

tags = _.flatten(tags);
// gives us ['tag1', 'tag2', 'tag2', 'tag1', 'tag3', 'tag4', 'tag3', 'tag4']

最后,您只需要每个标记的一个实例。

  

uniq _.uniq(array, [isSorted], [iterator])别名:unique

     

使用===生成数组的无副本版本,以测试对象相等性。如果您事先知道数组已排序,则为isSorted传递true将运行更快的算法。如果要根据转换计算唯一项,请传递迭代器函数。

tags = _.unique(tags)
// gives us ['tag1', 'tag2', 'tag3', 'tag4']

我们可以将这些与Underscore的有用chain方法结合在一起,将这些组合在一起。让我们在返回唯一标记的范围上创建一个函数:

$scope.uniqueTags = function() {
  return _.chain($scope.list)
    .pluck('tags')
    .flatten()
    .unique()
    .value();
};

由于这是一个函数,因此无论我们是否在$scope.list之后添加或删除项目,它都将始终返回唯一标记。

现在,您可以使用ng-repeat上的uniqueTags来显示每个代码:

<div ng-repeat="tag in uniqueTags()">
  <label class="checkbox">
    <input type="checkbox" ng-model="filter.tag" />
    {{tag}}
  </label>
</div>

这是一个有效的jsFiddle演示了这种技术:http://jsfiddle.net/BinaryMuse/cqTKG/

答案 1 :(得分:3)

使用自定义过滤器获取唯一的标记集/数组,适用于ng-repeat:

.filter('uniqueTags', function() {
    return function(list) {
        var tags = {};
        angular.forEach(list, function(obj, key) {
            angular.forEach(obj.tags, function(value) {
                tags[value] = 1;
            })
        });
        var uniqueTags = []
        for (var key in tags) {
            uniqueTags.push(key);
        }
        return uniqueTags;
    }
});

我首先将标签放入一个对象中,这会自动赋予我们唯一性。然后我将它转换为数组。

使用如下:

<div ng-repeat="tag in list | uniqueTags">

Fiddle


以下情况可能与我认为您可能不希望/希望它做的事情有关:

<input type="checkbox" ng-model="filter.tag">

这不会在控制器范围(即使用ng-repeat的范围)上创建$ scope属性filter.tag1filter.tag2。 ng-repeat的每次迭代都会创建自己的子范围,因此上面的ng-model将在每个ng-repeat子范围上创建范围属性filter.tag,如我的小提琴所示。