Javascript 如何使用 Angular 过滤器对数据进行分组?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14800862/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I group data with an Angular filter?
提问by Benny Bottema
I have a list of players which belong to a group each. How can I use a filter to list the users per group?
我有一个玩家列表,每个玩家都属于一个组。如何使用过滤器列出每个组的用户?
[{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'}];
I'm looking for this result:
我正在寻找这个结果:
- team alpha
- Gene
- team beta
- George
- Paula
- team gamma
- Steve
- Scruath of the 5th sector
- 团队阿尔法
- 基因
- 团队测试版
- 乔治
- 宝拉
- 团队伽马
- 史蒂夫
- 第 5 部门的 Scruath
回答by a8m
You can use groupBy of angular.filtermodule.
so you can do something like this:
您可以使用angular.filter模块的groupBy。
所以你可以做这样的事情:
JS:
JS:
$scope.players = [
{name: 'Gene', team: 'alpha'},
{name: 'George', team: 'beta'},
{name: 'Steve', team: 'gamma'},
{name: 'Paula', team: 'beta'},
{name: 'Scruath', team: 'gamma'}
];
HTML:
HTML:
<ul ng-repeat="(key, value) in players | groupBy: 'team'">
Group name: {{ key }}
<li ng-repeat="player in value">
player: {{ player.name }}
</li>
</ul>
RESULT:
Group name: alpha
* player: Gene
Group name: beta
* player: George
* player: Paula
Group name: gamma
* player: Steve
* player: Scruath
结果:
组名:alpha
* 玩家:Gene
组名:beta
* 玩家:George
* 玩家:Paula
组名:gamma
* 玩家:Steve
* 玩家:Scruath
UPDATE:jsbinRemember the basic requirements to use angular.filter, specifically note you must add it to your module's dependencies:
更新:jsbin记住使用的基本要求angular.filter,特别注意你必须将它添加到你的模块的依赖项中:
(1) You can install angular-filter using 4 different methods:
- clone & build this repository
- via Bower: by running $ bower install angular-filter from your terminal
- via npm: by running $ npm install angular-filter from your terminal
- via cdnjs http://www.cdnjs.com/libraries/angular-filter
(2) Include angular-filter.js (or angular-filter.min.js) in your index.html, after including Angular itself.
(3) Add 'angular.filter' to your main module's list of dependencies.
(1) 您可以使用 4 种不同的方法安装 angular-filter:
- 克隆并构建此存储库
- 通过 Bower:通过从终端运行 $ bower install angular-filter
- 通过 npm:通过从终端运行 $ npm install angular-filter
- 通过 cdnjs http://www.cdnjs.com/libraries/angular-filter
(2) 在 index.html 中包含 angular-filter.js(或 angular-filter.min.js),在包含 Angular 本身之后。
(3) 将 'angular.filter' 添加到主模块的依赖项列表中。
回答by chrisv
In addition to the accepted answers above I created a generic 'groupBy' filter using the underscore.js library.
除了上面接受的答案之外,我还使用 underscore.js 库创建了一个通用的“groupBy”过滤器。
JSFiddle (updated): http://jsfiddle.net/TD7t3/
JSFiddle(更新):http: //jsfiddle.net/TD7t3/
The filter
过滤器
app.filter('groupBy', function() {
return _.memoize(function(items, field) {
return _.groupBy(items, field);
}
);
});
Note the 'memoize' call. This underscore method caches the result of the function and stops angular from evaluating the filter expression every time, thus preventing angular from reaching the digest iterations limit.
注意 'memoize' 调用。这个下划线方法缓存函数的结果并阻止 angular 每次评估过滤器表达式,从而防止 angular 达到摘要迭代限制。
The html
html
<ul>
<li ng-repeat="(team, players) in teamPlayers | groupBy:'team'">
{{team}}
<ul>
<li ng-repeat="player in players">
{{player.name}}
</li>
</ul>
</li>
</ul>
We apply our 'groupBy' filter on the teamPlayers scope variable, on the 'team' property. Our ng-repeat receives a combination of (key, values[]) that we can use in our following iterations.
我们将“groupBy”过滤器应用于“team”属性上的 teamPlayers 范围变量。我们的 ng-repeat 接收一个 (key, values[]) 的组合,我们可以在接下来的迭代中使用它。
Update June 11th 2014I expanded the group by filter to account for the use of expressions as the key (eg nested variables). The angular parse service comes in quite handy for this:
2014 年 6 月 11 日更新我通过过滤器扩展了组以考虑使用表达式作为键(例如嵌套变量)。角度解析服务为此非常方便:
The filter (with expression support)
过滤器(带表达式支持)
app.filter('groupBy', function($parse) {
return _.memoize(function(items, field) {
var getter = $parse(field);
return _.groupBy(items, function(item) {
return getter(item);
});
});
});
The controller (with nested objects)
控制器(带有嵌套对象)
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}];
});
The html (with sortBy expression)
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/
JSFiddle:http: //jsfiddle.net/k7fgB/2/
回答by Benny Bottema
First do a loop using a filter that will return only unique teams, and then a nested loop that returns all players per current team:
首先使用过滤器进行循环,只返回唯一的球队,然后嵌套循环,返回每个当前球队的所有球员:
http://jsfiddle.net/plantface/L6cQN/
http://jsfiddle.net/plantface/L6cQN/
html:
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>
script:
脚本:
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;
}
}
回答by Walter Stabosz
I originally used Plantface's answer, but I didn't like how the syntax looked in my view.
我最初使用 Plantface 的答案,但我不喜欢语法在我看来的样子。
I reworked it to use $q.deferto post-process the data and return a list on unique teams, which is then uses as the filter.
我对其进行了修改,以使用$q.defer对数据进行后处理并返回一个关于独特团队的列表,然后将其用作过滤器。
http://plnkr.co/edit/waWv1donzEMdsNMlMHBa?p=preview
http://plnkr.co/edit/waWv1donzEMdsNMlMHBa?p=preview
View
看法
<ul>
<li ng-repeat="team in teams">{{team}}
<ul>
<li ng-repeat="player in players | filter: {team: team}">{{player.name}}</li>
</ul>
</li>
</ul>
Controller
控制器
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);
});
回答by Theo
Both answers were good so I moved them in to a directive so that it is reusable and a second scope variable doesn't have to be defined.
两个答案都很好,所以我将它们移到了一个指令中,这样它就可以重用,并且不必定义第二个作用域变量。
Here is the fiddleif you want to see it implemented
如果你想看到它的实现,这是小提琴
Below is the directive:
下面是指令:
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);
};
});
Then it can be used as follows:
然后它可以如下使用:
<div ng-repeat="team in players|groupBy:'team'">
<b>{{team}}</b>
<li ng-repeat="player in players | filter: {team: team}">{{player.name}}</li>
</div>
回答by Josep
Update
更新
I initially wrote this answer because the old version of the solution suggested by Ariel M. when combined with other $filterstriggered an "Infite $diggest Loop Error" (infdig). Fortunately this issue has been solved in the latest version of the angular.filter.
我最初写这个答案是因为 Ariel M. 建议的旧版本解决方案与其他$filters结合时触发了“ Infite $diggest Loop Error”( infdig)。幸运的是,这个问题已经在最新版本的angular.filter 中得到解决。
I suggested the following implementation, that didn't have that issue:
我建议了以下实现,没有那个问题:
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;
};
});
However, this implementation will only work with versions prior to Angular 1.3. (I will update this answer shortly providing a solution that works with all versions.)
但是,此实现仅适用于 Angular 1.3 之前的版本。(我将很快更新此答案,提供适用于所有版本的解决方案。)
I've actually wrote a post about the steps that I took to develop this $filter, the problems that I encountered and the things that I learned from it.
回答by Luis Teijon
In addition to the accepted answer you can use this if you want to group by multiple columns:
除了接受的答案之外,如果您想按多列分组,您可以使用它:
<ul ng-repeat="(key, value) in players | groupBy: '[team,name]'">
回答by trueboroda
If you need that in js code. You can use injected method of angula-filter lib. Like this.
如果您需要在 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
https://github.com/a8m/angular-filter/wiki/Common-Questions#inject-filters

