Reputation: 619
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.
Upvotes: 0
Views: 229
Reputation: 842
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.
Upvotes: 2
Reputation: 439
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)
Upvotes: 0
Reputation: 1522
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.
Upvotes: 0
Reputation: 44
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 %
Upvotes: 0