如何使用角度滤波器对数据进行分组?

我有一份球员名单,每个球员都属于一个小组。如何使用筛选器列出每个组的用户?

[{name: 'Gene', team: 'team alpha'},
{name: 'George', team: 'team beta'},
{name: 'Steve', team: 'team gamma'},
{name: 'Paula', team: 'team beta'},
{name: 'Scruath of the 5th sector', team: 'team gamma'}];

我在寻找这个结果:

  • A 队
    • 吉恩
  • 贝塔队
    • 乔治
    • 宝拉
  • 伽马小队
    • 史蒂夫
    • 第五区的斯克鲁斯
179240 次浏览

首先使用一个只返回唯一球队的过滤器执行一个循环,然后使用一个嵌套循环返回每个当前球队的所有球员:

Http://jsfiddle.net/plantface/l6cqn/

Html:

<div ng-app ng-controller="Main">
<div ng-repeat="playerPerTeam in playersToFilter() | filter:filterTeams">
<b>\{\{playerPerTeam.team}}</b>
<li ng-repeat="player in players | filter:{team: playerPerTeam.team}">\{\{player.name}}</li>
</div>
</div>

剧本:

function Main($scope) {
$scope.players = [{name: 'Gene', team: 'team alpha'},
{name: 'George', team: 'team beta'},
{name: 'Steve', team: 'team gamma'},
{name: 'Paula', team: 'team beta'},
{name: 'Scruath of the 5th sector', team: 'team gamma'}];


var indexedTeams = [];


// this will reset the list of indexed teams each time the list is rendered again
$scope.playersToFilter = function() {
indexedTeams = [];
return $scope.players;
}


$scope.filterTeams = function(player) {
var teamIsNew = indexedTeams.indexOf(player.team) == -1;
if (teamIsNew) {
indexedTeams.push(player.team);
}
return teamIsNew;
}
}

我最初使用的是 Plantface 的答案,但我不喜欢在我的视图中看到的语法。

我重新编写了它,使用 $q.defer对数据进行后处理,并返回一个独特团队的列表,然后将其用作过滤器。

Http://plnkr.co/edit/wawv1donzemdsnmlmhba?p=preview

观景

<ul>
<li ng-repeat="team in teams">\{\{team}}
<ul>
<li ng-repeat="player in players | filter: {team: team}">\{\{player.name}}</li>
</ul>
</li>
</ul>

控制员

app.controller('MainCtrl', function($scope, $q) {


$scope.players = []; // omitted from SO for brevity


// create a deferred object to be resolved later
var teamsDeferred = $q.defer();


// return a promise. The promise says, "I promise that I'll give you your
// data as soon as I have it (which is when I am resolved)".
$scope.teams = teamsDeferred.promise;


// create a list of unique teams. unique() definition omitted from SO for brevity
var uniqueTeams = unique($scope.players, 'team');


// resolve the deferred object with the unique teams
// this will trigger an update on the view
teamsDeferred.resolve(uniqueTeams);


});

这两个答案都很好,所以我将它们移动到一个指令中,这样它就可以重用,并且不需要定义第二个范围变量。

如果您希望看到它的实现,这里是小提琴

下面是指示:

var uniqueItems = function (data, key) {
var result = [];
for (var i = 0; i < data.length; i++) {
var value = data[i][key];
if (result.indexOf(value) == -1) {
result.push(value);
}
}
return result;
};


myApp.filter('groupBy',
function () {
return function (collection, key) {
if (collection === null) return;
return uniqueItems(collection, key);
};
});

然后,它可以用于以下方面:

<div ng-repeat="team in players|groupBy:'team'">
<b>\{\{team}}</b>
<li ng-repeat="player in players | filter: {team: team}">\{\{player.name}}</li>
</div>

除了上面已经接受的答案之外,我还使用 underscore.js 库创建了一个通用的“ groupBy”过滤器。

JSFiddle (更新) : Http://jsfiddle.net/td7t3/

过滤器

app.filter('groupBy', function() {
return _.memoize(function(items, field) {
return _.groupBy(items, field);
}
);
});

请注意“制表”调用。这个下划线方法缓存函数的结果,并且每次都阻止棱角计算过滤器表达式,从而防止棱角达到摘要迭代的极限。

超文本标记语言

<ul>
<li ng-repeat="(team, players) in teamPlayers | groupBy:'team'">
\{\{team}}
<ul>
<li ng-repeat="player in players">
\{\{player.name}}
</li>
</ul>
</li>
</ul>

我们将“ groupBy”过滤器应用于 team Player 范围变量的“ team”属性。我们的 ng-repeat 接收一组(key,value []) ,我们可以在以下迭代中使用它们。

2014年6月11日更新 我通过过滤器扩展了组,以说明表达式作为关键字的使用(例如嵌套变量)。角解析服务在这方面非常方便:

过滤器(带有表达式支持)

app.filter('groupBy', function($parse) {
return _.memoize(function(items, field) {
var getter = $parse(field);
return _.groupBy(items, function(item) {
return getter(item);
});
});
});

控制器(带有嵌套对象)

app.controller('homeCtrl', function($scope) {
var teamAlpha = {name: 'team alpha'};
var teamBeta = {name: 'team beta'};
var teamGamma = {name: 'team gamma'};


$scope.teamPlayers = [{name: 'Gene', team: teamAlpha},
{name: 'George', team: teamBeta},
{name: 'Steve', team: teamGamma},
{name: 'Paula', team: teamBeta},
{name: 'Scruath of the 5th sector', team: teamGamma}];
});

Html (带有 sortBy 表达式)

<li ng-repeat="(team, players) in teamPlayers | groupBy:'team.name'">
\{\{team}}
<ul>
<li ng-repeat="player in players">
\{\{player.name}}
</li>
</ul>
</li>

JSFiddle: Http://jsfiddle.net/k7fgb/2/

可以使用 棱角过滤器模块的 groupBy。
所以你可以这样做:

约翰逊:

$scope.players = [
{name: 'Gene', team: 'alpha'},
{name: 'George', team: 'beta'},
{name: 'Steve', team: 'gamma'},
{name: 'Paula', team: 'beta'},
{name: 'Scruath', team: 'gamma'}
];

HTML:

<ul ng-repeat="(key, value) in players | groupBy: 'team'">
Group name: \{\{ key }}
<li ng-repeat="player in value">
player: \{\{ player.name }}
</li>
</ul>

结果:
组名: Alpha
吉恩
组名: 贝塔
* 播放器: 乔治
* Player: Paula
组名: 伽玛
史蒂夫 *
* 玩家: 斯克鲁阿斯

更新: Jsbin记住使用 angular.filter的基本要求,特别要注意你必须将它添加到模块的依赖项中:

(1)你可以使用4种不同的方法安装角度滤波器:

  1. 克隆并构建此存储库
  2. 通过 Bower: 从你的终端运行 $Bower 安装角过滤器
  3. 通过 npm: 通过运行 $npm 从您的终端安装角过滤器
  4. 通过 cdnjs http://www.cdnjs.com/libraries/angular-filter

(2)在你的 index.html 中包含角过滤器. js (或者角过滤器. min.js) ,在包含角本身之后。

(3)将‘ angular.filter’添加到主模块的依赖项列表中。

更新

我最初写这个答案是因为 Ariel M. 当与其他 $filter结合时提出的解决方案的旧版本触发了 “ < em > Inite $digges 循环错误 ”(infdig)。幸运的是,这个问题已经在最新版本的 棱角过滤器中得到解决。

我建议实施以下 没有这个问题:

angular.module("sbrpr.filters", [])
.filter('groupBy', function () {
var results={};
return function (data, key) {
if (!(data && key)) return;
var result;
if(!this.$id){
result={};
}else{
var scopeId = this.$id;
if(!results[scopeId]){
results[scopeId]={};
this.$on("$destroy", function() {
delete results[scopeId];
});
}
result = results[scopeId];
}


for(var groupKey in result)
result[groupKey].splice(0,result[groupKey].length);


for (var i=0; i<data.length; i++) {
if (!result[data[i][key]])
result[data[i][key]]=[];
result[data[i][key]].push(data[i]);
}


var keys = Object.keys(result);
for(var k=0; k<keys.length; k++){
if(result[keys[k]].length===0)
delete result[keys[k]];
}
return result;
};
});

但是,这个实现只能在 Angular 1.3之前的版本中使用。(我将很快更新这个答案,提供一个可以使用所有版本的解决方案。)

实际上我有 写了一篇关于我开发这个 $filter的步骤,我遇到的问题和我从中学到的东西的文章

除了公认的答案,如果你想按 多列分组,你可以使用这个:

<ul ng-repeat="(key, value) in players | groupBy: '[team,name]'">

如果在 js 代码中需要,可以使用 angula-filter 的注入方法 lib。 像这样。

function controller($scope, $http, groupByFilter) {


var groupedData = groupByFilter(originalArray, 'groupPropName');


}

Https://github.com/a8m/angular-filter/wiki/common-questions#inject-filters