How can I group data with an Angular filter? How can I group data with an Angular filter? angularjs angularjs

How can I group data with an Angular filter?


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

JS:

$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>

RESULT:
Group name: alpha
* player: Gene
Group name: beta
* player: George
* player: Paula
Group name: 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:

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

  1. clone & build this repository
  2. via Bower: by running $ bower install angular-filter from your terminal
  3. via npm: by running $ npm install angular-filter from your terminal
  4. 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.


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

JSFiddle (updated):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.

The 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.

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:

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)

<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/


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/

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