Sharing Top Content from the Angular-sphere.

[SOLVED] How can I group data with an Angular filter?- Angular.js Recipes

  • [{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:

    You can use groupBy of angular.filter module.

  • so you can do something like this: $scope.players = [ {name: ‘Gene’, team: ‘alpha’}, {name: ‘George’, team: ‘beta’}, {name: ‘Steve’, team: ‘gamma’}, {name: ‘Paula’, team: ‘beta’}, {name: ‘Scruath’, team: ‘gamma’} ];
      Group name: {{ key }}

    • player: {{ player.name }}

    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 , specifically note you must add it to your module’s dependencies: (1) You can install angular-filter using 4 different methods: via Bower: by running $ bower install angular-filter from your terminal via npm: by running $ npm install angular-filter from your terminal (2) Include angular-filter.

  • Here is the fiddle if you want to see it implemented 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: I originally used Plantface's answer, but I didn't like how the syntax looked in my view.
  • 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 });

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

  • The angular parse service comes in quite handy for this: 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}]; });

    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: 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 = == -1; if (teamIsNew) { } return teamIsNew; } }

    This recipe can be found in it’s original form on Stack Over Flow.

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:

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.


@angular_recipe: How can I group data with an Angular filter? #Angular #AngularJS

In addition to the accepted answer you can use this if you want to group by multiple columns:

    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:

    {{team}}

  • {{player.name}}
  • I originally used Plantface’s answer, but I didn’t like how the syntax looked in my view.

    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.

    • {{team}}
      • {{player.name}}

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

    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

    • {{team}}
      • {{player.name}}

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

    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)

  • {{team}}
    • {{player.name}}
  • 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:

    html:

    {{playerPerTeam.team}}

  • {{player.name}}
  • 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; } }

    ). Fortunately this issue has been solved in the latest version of the 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

[SOLVED] How can I group data with an Angular filter?- Angular.js Recipes

Comments are closed, but trackbacks and pingbacks are open.