1

I have an array of objects of the form

widgets = [
    {
        id: 1,
        created: '12/1/2017',
        weight: 2
    },
    {
        id: 2,
        created: '12/1/2017',
        weight: 1
    },
    {
        id: 3,
        created: '12/2/2017',
        weight: 2
    },
    {
        id: 4,
        created: '12/3/2017',
        weight: 2
    }
]

Currently to get the organization I'm after I 'massage' the data so that I can iterate through it with *ngFor loops to produce panels which look something like

|12/1/2017    |
| ID | Weight |
| 1  |      2 |
| 2  |      1 |
|12/2/2017    |
| ID | Weight |
| 3  |      2 |
|13/3/2017    |
| ID | Weight |
| 4  |      2 |

So after the 'massaging' the above widgets array looks like the below array

widgets = [
    {
        date: '12/1/2017',
        recs: [
            {
                id: 1,
                created: '12/1/2017',
                weight: 2
            },
            {
            id: 2,
                created: '12/1/2017',
                weight: 1
            }
        ]
    },
    {
        date: '12/2/2017',
        recs: [
            {
                id: 3,
                created: '12/2/2017',
                weight: 2
            }
        ]
    },
    {
        date: '12/3/2017',
        recs: [
            {
                id: 4,
                created: '12/3/2017',
                weight: 2
            }
        ]
    }
]

Is there some templating trick I can do with Angular4 to get the panel grouping I'm after without having to reorganize my original array structure?

Perhaps a directive I can place on an element in my template to achieve this?

gh0st
  • 1,653
  • 3
  • 27
  • 59

1 Answers1

0

Short answer is no.

It looks like you are trying to do a group by. There are some other/older posts on SO. - How to group data in Angular 2?

However, Angular suggests that you don't do a lot of data manipulation in the template for performance reasons. So 'massaging' the data prior or binding in the template is probably the most efficient path.

If you need to keep the data in its original structure. Why not just reduce the original data to a workable format that just points to the original data.

Example:

const widgets = [
    {
        id: 1,
        created: '12/1/2017',
        weight: 2
    },
    {
        id: 2,
        created: '12/1/2017',
        weight: 1
    },
    {
        id: 3,
        created: '12/2/2017',
        weight: 2
    },
    {
        id: 4,
        created: '12/3/2017',
        weight: 2
    }
]

-

const groupings = [
    {
        date: '12/1/2017',
        recs: [1,2]
    },
    {
        date: '12/2/2017',
        recs: [3]
    },
    {
        date: '12/3/2017',
        recs: [4]
    }
]

-

// template

<div *ngFor="let group of groupings">
    <h1>{{group.date}}</h1>
    <p *ngFor="let indx of group.recs">{{widgets[indx]}}</p>
</div>

This way you can bind to the original data structure, and it will account for any duplicate entries across groupings. You may prefer to store data like this (re: widgets) in a Map structure as opposed to an array.

joshvito
  • 1,498
  • 18
  • 23
  • I studied the plunker in that referenced post of yours and forked it. Why wouldn't something like [this](https://plnkr.co/edit/1nmcIZwN61FtFfGTefIw?p=preview) work (reference line 40)? I suppose this is exactly what you mean by 'angular suggests not doing a lot of data manipulation in the template". – gh0st Dec 29 '17 at 21:12
  • that Plnk doesn't render for me, it has a template parse error. Put a console.log() call in the pipe, and then you can see how many times it get called on load and when you interactively update the data set. – joshvito Jan 02 '18 at 14:03
  • Ya I'm trying to do `*ngFor="let employee of employees.filter(employee => { employee.department === item.key })"` but I get `Parser Error: Bindings cannot contain assignments at column 44 in [let employee of employees.filter(employee => { employee.department === item.key })] in ng:///AppModule/App.html@12:12`; in that plnk that doesn't load. I was just trying something. But I guess it doesn't work like that... – gh0st Jan 02 '18 at 15:57
  • yea, angular doesn't allow binding like that. Filtering a data set in template with a filter pipe is well documented. You could pass in the `item.key`; let me see if I can update your Plunk for you. – joshvito Jan 02 '18 at 16:09
  • 1
    @gh0st here you go, I made [your Plunk work](https://plnkr.co/edit/2b34aNH6HTsZ2MyEtlgT?p=preview); However, you will notice the pipes will get called on every Change Detection cycle. This will be less efficient that storing the data like you need it as stated above. – joshvito Jan 02 '18 at 16:28
  • 1
    You are also iterating over the 'employees' array multiple times per view refresh. – joshvito Jan 02 '18 at 16:36
  • And this is probably why the angular team left out the filter pipe in the first place? – gh0st Jan 02 '18 at 16:50
  • yes, they discuss why they left it out in the docs @ https://angular.io/guide/pipes#appendix-no-filterpipe-or-orderbypipe – joshvito Jan 02 '18 at 17:18