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

时间:2021-03-11 07:38:54

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区斯科拉斯
  • 第五部门的团队伽玛。

7 个解决方案

#1


162  

You can use groupBy of angular.filter module.
so you can do something like this:

你可以用有角的群。过滤模块。你可以这样做:

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 * player:基因组名:beta * player: George * player: Paula组名:gamma * player: Steve * player: Scruath

UPDATE: jsbin Remember the basic requirements to use angular.filter, specifically note you must add it to your module's dependencies:

更新:jsbin记住使用角的基本要求。过滤器,特别注意您必须将它添加到模块的依赖项中:

(1) You can install angular-filter using 4 different methods:

(1)可以使用4种不同的方法安装angular-filter:

  1. clone & build this repository
  2. 克隆并构建此存储库
  3. via Bower: by running $ bower install angular-filter from your terminal
  4. 通过Bower:通过运行$ Bower从终端安装angular-filter
  5. via npm: by running $ npm install angular-filter from your terminal
  6. 通过npm:通过运行$ npm从终端安装angular-filter。
  7. via cdnjs http://www.cdnjs.com/libraries/angular-filter
  8. 通过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.

(2)包括angular-filter。在你的索引中。html,包含角本身之后。

(3) Add 'angular.filter' to your main module's list of dependencies.

(3)添加的角。过滤到主模块的依赖项列表中。

#2


23  

In addition to the accepted answers above I created a generic 'groupBy' filter using the underscore.js library.

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

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的电话。这个下划线方法缓存了函数的结果,并且每次都停止了对过滤器表达式的求角,从而防止了角度达到摘要迭代的极限。

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.

我们在“团队”属性的teamPlayers作用域变量上应用“groupBy”过滤器。我们的ng-repeat接收(key, values[])的组合,我们可以在后续迭代中使用它们。

Update June 11th 2014 I 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/

#3


19  

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;
    }
}

#4


16  

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.defer to post-process the data and return a list on unique teams, which is then uses as the filter.

我对它进行了修改,使用$q. deferred来处理数据,并返回一个关于唯一团队的列表,然后这个列表作为过滤器使用。

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);

});

#5


11  

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 fiddle if 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>

#6


11  

Update

I initially wrote this answer because the old version of the solution suggested by Ariel M. when combined with other $filters triggered an "Infite $diggest Loop Error" (infdig). Fortunately this issue has been solved in the latest version of the angular.filter.

我最初写下这个答案是因为Ariel M.建议的旧版本的解决方案与其他$filter结合时触发了“Infite $diggest循环错误”(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.)

但是,这个实现只会在角度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.

我写了一篇关于我开发这个过滤器的步骤,我遇到的问题以及我从中学到的东西。

#7


1  

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]'">

#1


162  

You can use groupBy of angular.filter module.
so you can do something like this:

你可以用有角的群。过滤模块。你可以这样做:

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 * player:基因组名:beta * player: George * player: Paula组名:gamma * player: Steve * player: Scruath

UPDATE: jsbin Remember the basic requirements to use angular.filter, specifically note you must add it to your module's dependencies:

更新:jsbin记住使用角的基本要求。过滤器,特别注意您必须将它添加到模块的依赖项中:

(1) You can install angular-filter using 4 different methods:

(1)可以使用4种不同的方法安装angular-filter:

  1. clone & build this repository
  2. 克隆并构建此存储库
  3. via Bower: by running $ bower install angular-filter from your terminal
  4. 通过Bower:通过运行$ Bower从终端安装angular-filter
  5. via npm: by running $ npm install angular-filter from your terminal
  6. 通过npm:通过运行$ npm从终端安装angular-filter。
  7. via cdnjs http://www.cdnjs.com/libraries/angular-filter
  8. 通过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.

(2)包括angular-filter。在你的索引中。html,包含角本身之后。

(3) Add 'angular.filter' to your main module's list of dependencies.

(3)添加的角。过滤到主模块的依赖项列表中。

#2


23  

In addition to the accepted answers above I created a generic 'groupBy' filter using the underscore.js library.

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

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的电话。这个下划线方法缓存了函数的结果,并且每次都停止了对过滤器表达式的求角,从而防止了角度达到摘要迭代的极限。

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.

我们在“团队”属性的teamPlayers作用域变量上应用“groupBy”过滤器。我们的ng-repeat接收(key, values[])的组合,我们可以在后续迭代中使用它们。

Update June 11th 2014 I 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/

#3


19  

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;
    }
}

#4


16  

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.defer to post-process the data and return a list on unique teams, which is then uses as the filter.

我对它进行了修改,使用$q. deferred来处理数据,并返回一个关于唯一团队的列表,然后这个列表作为过滤器使用。

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);

});

#5


11  

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 fiddle if 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>

#6


11  

Update

I initially wrote this answer because the old version of the solution suggested by Ariel M. when combined with other $filters triggered an "Infite $diggest Loop Error" (infdig). Fortunately this issue has been solved in the latest version of the angular.filter.

我最初写下这个答案是因为Ariel M.建议的旧版本的解决方案与其他$filter结合时触发了“Infite $diggest循环错误”(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.)

但是,这个实现只会在角度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.

我写了一篇关于我开发这个过滤器的步骤,我遇到的问题以及我从中学到的东西。

#7


1  

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]'">