0

I have a table and I want to render headers grouped by group property from object in array. The array with the headers looks like this:

const headers = [
 { label: 'Date', group: '' },
 { label: 'Event', group: '' },
 { label: 'Days Out', group: '' },
 { label: 'T', group: 'Sales Velocity' },
 { label: '-1', group: 'Sales Velocity' },
 { label: '-2', group: 'Sales Velocity' },
 { label: '-3', group: 'Sales Velocity' },
 { label: '-4', group: 'Sales Velocity' },
 { label: 'Sold Last 5', group: 'Ticket Sales' },
 { label: 'Total Sold', group: 'Ticket Sales' },
 { label: 'Sellable cap.', group: 'Ticket Sales' },
 { label: '% sold', group: 'Ticket Sales' },
 { label: 'Availab.', group: 'Ticket Sales' },
 { label: 'Total', group: 'Revenue' },
 { label: 'Holds', group: 'Inventory Status' },
 { label: 'Comp', group: 'Inventory Status' },
 { label: 'Open', group: 'Inventory Status' },
 { label: 'Price cat.', group: 'Inventory Status' },
 { label: 'Avg. price', group: 'Stats' },
 { label: 'First time %', group: 'Stats' },
];

and the table component looks like this:

<TableHead>
 <TableRow>
 {headers.map((header, index) => (
 <TableCellASHeader key={index}>
 <TableSortLabel
 active={header.column === sorting.orderBy}
 direction={sorting.orderDirection}
 onClick={() => onClickSort(header.column)}
 IconComponent={ArrowDropDownIcon}
 >
 {/* {header.group} */} // here I need to render group but only once per group
 {header.label}
 </TableSortLabel>
 </TableCellASHeader>
 ))}
 </TableRow>
 </TableHead>

What I want is to render header.group above header.label but only once per group, like on this picture below. Any code sample will be appreciated. enter image description here

asked Jul 3, 2020 at 11:42
5
  • filter the array Commented Jul 3, 2020 at 11:50
  • 2
    You might want to take a look at this answer, or if you don't mind using libraries, you could try Lodash's groupBy() method. Commented Jul 3, 2020 at 11:52
  • and make new arrays with given type I mean Sales Velocity ['T','-1', '-2', '-3', '-4'] Ticket Sales[] Revenue[] Inventory Status[] Stats[] (I skipped the data) Commented Jul 3, 2020 at 11:56
  • @grzesiekmq can you please write a sample of how to do this? thanks Commented Jul 3, 2020 at 11:58
  • ok I wrote code Commented Jul 3, 2020 at 13:26

4 Answers 4

2

First of all, I would club the headers into an object based on group.

const groupedHeaders = headers.reduce((acc, curr) => {
 let {group, label} = curr;
 if (!group) group = 'empty';
 if (!acc[group]) {
 acc[group] = [label]
 } else {
 acc[group] = [...acc[group], label]
 }
 return acc;
}, {});

After clubbing them up, the groupedHeaders would look like this -

{
 empty: [ 'Date', 'Event', 'Days Out' ],
 'Sales Velocity': [ 'T', '-1', '-2', '-3', '-4' ],
 'Ticket Sales': [
 'Sold Last 5',
 'Total Sold',
 'Sellable cap.',
 '% sold',
 'Availab.'
 ],
 Revenue: [ 'Total' ],
 'Inventory Status': [ 'Holds', 'Comp', 'Open', 'Price cat.' ],
 Stats: [ 'Avg. price', 'First time %' ]
}

Rendering in React part would make use of Object.entries() to iterate through the object and display accordingly.

Object.entries(groupedHeaders).map(([group, labels]) => {
 <TableRow>
 <HeaderGroup> // you will need to add css with flex/grid
 {group === 'empty' ? <EmptyHeader /> : <GroupHeader />}
 <SubHeaderGroup> // css required for grouping
 {labels.map((header, index) => (
 <TableCellASHeader key={index}>
 <TableSortLabel
 active={header.column === sorting.orderBy}
 ....
 </TableCellASHeader>
 ))}
 </SubHeaderGroup>
 </YourHeaderGroup>
 </TableRow>
});

Check out this Code Sandbox link for the full version of code.

answered Jul 3, 2020 at 12:16
Sign up to request clarification or add additional context in comments.

3 Comments

Can you tell me how would these <EmptyHeader /> and <YourHeaderElement /> look like? Thanks
Sure. Check this codesandbox link. I have tried to create something similar to the mockup using the logic above, but with very basic styling.
That's it! Thank you very much!
0

you can use new Set() and store group name in that and check each time when map function run. I have done this in javascript it will print group name 1 time and label many times., Check this

const headers = [
 { label: 'Date', group: '' },
 { label: 'Event', group: '' },
 { label: 'Days Out', group: '' },
 { label: 'T', group: 'Sales Velocity' },
 { label: '-1', group: 'Sales Velocity' },
 { label: '-2', group: 'Sales Velocity' },
 { label: '-3', group: 'Sales Velocity' },
 { label: '-4', group: 'Sales Velocity' },
 { label: 'Sold Last 5', group: 'Ticket Sales' },
 { label: 'Total Sold', group: 'Ticket Sales' },
 { label: 'Sellable cap.', group: 'Ticket Sales' },
 { label: '% sold', group: 'Ticket Sales' },
 { label: 'Availab.', group: 'Ticket Sales' },
 { label: 'Total', group: 'Revenue' },
 { label: 'Holds', group: 'Inventory Status' },
 { label: 'Comp', group: 'Inventory Status' },
 { label: 'Open', group: 'Inventory Status' },
 { label: 'Price cat.', group: 'Inventory Status' },
 { label: 'Avg. price', group: 'Stats' },
 { label: 'First time %', group: 'Stats' },
];
let groups = new Set();
headers.map((header) => {
 if(!groups.has(header.group)){
 groups.add(header.group);
 console.log(header.group); 
 } 
 console.log(header.label);
})

Output

Date
Event
Days Out
Sales Velocity
T
-1
-2
-3
-4
Ticket Sales
Sold Last 5
Total Sold
Sellable cap.
% sold
Availab.
Revenue
Total
Inventory Status
Holds
Comp
Open
Price cat.
Stats
Avg. price
First time %
answered Jul 3, 2020 at 12:10

1 Comment

I've tried this, but I have trouble to render results to my table :/
0

You can alternatively use lodash/uniqBy to achieve this. If you are working on enterprise level application and using React/Angular, it’s worth considering. You can achieve the desired result in one line like below-

import uniqBy from ‘lodash/uniqBy’;
const modifiedArray = uniqBy(headers,’group’);

Also, it is always recommended to check beforehand if your data is undefined or not. So, the best way to do is like below-

import get from ‘lodash/get’;
const modifiedArray = uniqBy((get(headers, ‘response.data’, [])),’group’);

Considering headers array is part of your api and the path is response.data.headers.

Please Note: You need to install lodash as your dev dependency in your project. uniqBy method will show only unique values without any duplication.

answered Jul 3, 2020 at 12:17

Comments

0

for example this code with filter and map and optionally put arrays into object

const headers = [{
 label: 'Date',
 group: ''
 },
 {
 label: 'Event',
 group: ''
 },
 {
 label: 'Days Out',
 group: ''
 },
 {
 label: 'T',
 group: 'Sales Velocity'
 },
 {
 label: '-1',
 group: 'Sales Velocity'
 },
 {
 label: '-2',
 group: 'Sales Velocity'
 },
 {
 label: '-3',
 group: 'Sales Velocity'
 },
 {
 label: '-4',
 group: 'Sales Velocity'
 },
 {
 label: 'Sold Last 5',
 group: 'Ticket Sales'
 },
 {
 label: 'Total Sold',
 group: 'Ticket Sales'
 },
 {
 label: 'Sellable cap.',
 group: 'Ticket Sales'
 },
 {
 label: '% sold',
 group: 'Ticket Sales'
 },
 {
 label: 'Availab.',
 group: 'Ticket Sales'
 },
 {
 label: 'Total',
 group: 'Revenue'
 },
 {
 label: 'Holds',
 group: 'Inventory Status'
 },
 {
 label: 'Comp',
 group: 'Inventory Status'
 },
 {
 label: 'Open',
 group: 'Inventory Status'
 },
 {
 label: 'Price cat.',
 group: 'Inventory Status'
 },
 {
 label: 'Avg. price',
 group: 'Stats'
 },
 {
 label: 'First time %',
 group: 'Stats'
 },
];
const empty = headers.filter(el => el.group === '')
 .map(el => el.label)
console.log('empty', empty)
const sales = headers.filter(el => el.group === 'Sales Velocity')
 .map(el => el.label)
console.log('sales', sales)
const ticket = headers.filter(el => el.group === 'Ticket Sales')
 .map(el => el.label)
console.log('ticket', ticket)
const revenue = headers.filter(el => el.group === 'Revenue')
 .map(el => el.label)
console.log('revenue', revenue)
const inventory = headers.filter(el => el.group === 'Inventory Status')
 .map(el => el.label)
console.log('inventory', inventory)
const stats = headers.filter(el => el.group === 'Stats')
 .map(el => el.label)
console.log('stats', stats)
const obj = {}
obj.empty = empty
obj.sales = sales
obj.ticket = ticket
obj.revenue = revenue
obj.inventory = inventory
obj.stats = stats
console.log('obj', obj)

answered Jul 3, 2020 at 12:55

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.