0

I am in the process of updating some old AngularJS sites/apps to new versions of Angular and had a question around how to replace the old groupBy filter.

<li ng-repeat="(key, value) in attendees | groupBy: 'location'">
  <div class="item-title">{{ key }}</div>
  <div ng-repeat="attendee in value"><p>{{ attendee.name }}<span ng-if="attendee.description != ''">{{ attendee.description }}</span></p></div>
</li>

Here is a mockup of the attendees data:

[{
    "id": 1,
    "location": "United States",
    "name": "Walter Johnson",
    "description": ""
}, {
    "id": 2,
    "location": "Canada",
    "name": "Jerry Lewis",
    "description": ""
}, {
    "id": 3,
    "location": "Canada",
    "name": "Missy Mayer",
    "description": "5 Years"
}, {
    "id": 4,
    "location": "United States",
    "name": "Marvin Moore",
    "description": ""
}, {
    "id": 5,
    "location": "United States",
    "name": "Nelson Cooper",
    "description": ""
}]

Is there a way I can still create an item-title for each of the unique location items from the attendess data?

Thanks for any info or direction.

zeropsi
  • 682
  • 9
  • 24

1 Answers1

0

It's recommend by the angular team to avoid pipes that mutate data, which is why pipes like filter, orderBy, and groupBy are not built into Angular 2+. Instead just group the data in your controller. Here is how that could look like:

Controller:

export class AppComponent {
  name = "Angular " + VERSION.major;

  data = [
    {
      id: 1,
      location: "United States",
      name: "Walter Johnson",
      description: ""
    },
    {
      id: 2,
      location: "Canada",
      name: "Jerry Lewis",
      description: ""
    },
    {
      id: 3,
      location: "Canada",
      name: "Missy Mayer",
      description: "5 Years"
    },
    {
      id: 4,
      location: "United States",
      name: "Marvin Moore",
      description: ""
    },
    {
      id: 5,
      location: "United States",
      name: "Nelson Cooper",
      description: ""
    }
  ];
  groups = {};

  ngOnInit() {
    this.groups = this.data.reduce((acc, curr) => {
      if (!acc[curr.location]) {
        acc[curr.location] = [];
      }

      acc[curr.location].push(curr);

      return acc;
    }, {});
  }
}

Then in the template, you can use KeyValueMap in combination with *ngFor. KeyValuePipe would be to iterate over each key, or "group" in the object generated from Array.prototype.reduce() and *ngFor to iterate over each item in the group's array:

<ul>
  <li *ngFor="let item of groups | keyvalue">
    <div>location: {{item.key}}</div>
    <div>
      <div *ngFor="let location of item.value">{{location | json}}</div>
    </div>
  <li>
</ul>

Please note that there are libraries that expose filter, grouping, sorting pipes, but this answer is approaching it from the recommendation provided the document on pipes.

If you need to update the value of groups just execute the reduce function again when/if needed.

Hopefully that helps!

Alexander Staroselsky
  • 37,209
  • 15
  • 79
  • 91