How to show grouped array in Angular?

Viewed 635

I have an array of objects like this

[
  {"desc":"a", "menu": 1},{"desc":"b", "menu": 2},{"desc":"c", "menu": 1}, 
  {"desc":"d", "menu": 3},{"desc":"e", "menu": 3},{"desc":"f", "menu": 2}, 
  {"desc":"g", "menu": 1},{"desc":"g", "menu": 1},{"desc":"g", "menu": 4}, 
  {"desc":"g", "menu": 4},{"desc":"g", "menu": 4}
]

Fetched from an API.

Now i would show that objects with a *ngFor by setting them grouped by "menu" and by adding a label to it like this

Menu 1

{all objects of menu 1}

Menu 2

{all objects of menu 2}

Menu 3

{all objects of menu 3}

I would do something like this in *ngFor

*ngFor="let object of objects; let menu = 0"
     if menu !== object.menu
           menu === object.menu
       WRITE LABEL

But how could i implement it in a real case code?

4 Answers

I think we should group it before using *ngFor here is the solution

 function groupBy(array, fn) {
    return array.reduce(
      (acc, current) => {
        const groupName = typeof fn === 'string' ? current[fn] : fn(current);
        (acc[groupName] = acc[groupName] || []).push(current);
        return acc;
      },
      {}
    );
  }

 function toArray(obj) {
    return Object.keys(obj).map(k => obj[k]);
  }
  
  const data = [
  {"desc":"a", "menu": 1},{"desc":"b", "menu": 2},{"desc":"c", "menu": 1}, 
  {"desc":"d", "menu": 3},{"desc":"e", "menu": 3},{"desc":"f", "menu": 2}, 
  {"desc":"g", "menu": 1},{"desc":"g", "menu": 1},{"desc":"g", "menu": 4}, 
  {"desc":"g", "menu": 4},{"desc":"g", "menu": 4}
]

const groupMenu = groupBy(data, (item) => item.menu);

Then in template

<group *ngFor="let group of groupMenu">
  <menu *ngFor="let menu of group">
   <label>{{menu.desc}}</label>
  </menu>
</group>

You can use something like

ngOnInit(){
    var groups = new Set(this.array.map(item => item.menu))
    this.result = [];
    groups.forEach(g => 
      this.result.push({
        menu: g, 
        values: this.array.filter(i => i.menu === g)
      }
    ))
  }

and in HTML render data

<p>
    Start editing to see some magic happen :)
</p>
<div *ngFor="let item of result" border="1">
    <table>
        <tr>
            <th>Desc</th>
            <th>Menu</th>
        </tr>
        <ng-container>
            <tr>
                <td colspan="2">{{item.menu}}</td>
            </tr>
            <tr *ngFor="let value of item.values">
                <td>{{value.desc}}</td>
            </tr>
        </ng-container>
    </table>
    <div>

Please check the stackblitz that I made. https://stackblitz.com/edit/angular-4ekz4n

Happy coding :)

Write import statement in angular component

import { of } from 'rxjs';
import { groupBy, mergeMap } from 'rxjs/operators';

Then in ngOnInit()

ngOnInit():void{
on(
    {id: 1, name: 'JavaScript'},
    {id: 2, name: 'Parcel'},
    {id: 2, name: 'webpack'},
    {id: 1, name: 'TypeScript'},
    {id: 3, name: 'TSLint'}
).pipe(groupBy(a=>a.id)),
 mergeMap((group$) => group$.pipe(reduce((acc, cur) => [...acc, cur], []))),
)
.subscribe(p => console.log(p));

//Output

[ { id: 1, name: 'JavaScript'},
{ id: 1, name: 'TypeScript'} ]
[ { id: 2, name: 'Parcel'},
  { id: 2, name: 'webpack'} ]
[ { id: 3, name: 'TSLint'} ]

For more info Refer rxJS

You first need to update the structure of current array to the structure as shown below:

[
  {
    menu: 1,
    desc: ["a", "b"]
  },
  {
    menu: 2,
    desc: ["a1", "b1", "c1", "d1"]
  }
]

You can update by iterating current array in component ts file and organise as shown in above example.

After this, you can use this updated array in *ngFor in html for showing data.

Related