1

Similar to this related question, I want to group an array of objects, e.g., by team name

[
 {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'}
];

Unfortunately, the accepted answer using ng-repeat with a groupBy filter doesn't seem to work within an Angular Material expansion panel, which is what I'm trying to do: I want multiple expansion panels, one per team, which, when expanded, show the involved players.

I tried

<mat-expansion-panel ng-repeat="(key, value) in players | groupBy: 'team'">
    <mat-expansion-panel-header>
      <mat-panel-title>{{ key }}</mat-panel-title>
    </mat-expansion-panel-header>
    <li ng-repeat="player in value">
      {{player.name}}
    </li>
</mat-expansion-panel>

However, ng-repeatis not allowed inside the mat-expansion-panel. *ngFor is allowed but I don't know how to use it with the groupBy filter. *ngFor="let player in players | groupBy: 'team'" throws an error and I can't find any documentation.

1

1 Answer 1

4

You should make your own custom pipe to support GroupBy, also ng-repeat is an angularjs syntax, you should use ngFor.

Your custom pipe should look as,

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({name: 'groupBy'})
export class GroupByPipe implements PipeTransform {
    transform(collection: Array<any>, property: string): Array<any> {
         if(!collection) {
            return null;
        }

        const groupedCollection = collection.reduce((previous, current)=> {
            if(!previous[current[property]]) {
                previous[current[property]] = [current];
            } else {
                previous[current[property]].push(current);
            }

            return previous;
        }, {});

        return Object.keys(groupedCollection).map(key => ({ key, value: groupedCollection[key] }));
    }
}

STACKBLITZ DEMO

Sign up to request clarification or add additional context in comments.

2 Comments

Why would they remove functionality from AngularJS? I'd expect many people could benefit from a built-in "groupBy" pipe.
Follow up question: What if I'm trying to group by date, but not exact date (with time) only really year, month, day? I tried chaining pipes but it didn't work. I would probably have to drop the hour, minute, second, millisecond before, right?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.