I wanted to display the table as follows. So I created the following component as shown below named envTableComponent
. This component loops through the envResponse
and displays the project name and build.
export const envTableComponent = () => {
let envTable = [];
const headerTable = ['PROJECT NAME', 'BUILD']
const envResponse = [
{
"environment": "PROJECT 1",
"verticals": [
{
"projects": [
{
"name": "ITALY",
"runs": [
{
"build": "B2345",
}
]
}
]
}
]
},
{
"environment": "PROJECT 2",
"verticals": [
{
"projects": [
{
"name": "FRANCE",
"runs": [
{
"build": "A4322",
}
]
},
{
"name": "MOSCOW",
"runs": [
{
"build": "C3456",
}
]
}
]
}
]
},
],
const projects = [];
envResponse.forEach((envMetric) => {
envMetric.verticals.forEach((vertical) => {
vertical.projects.forEach((project) => {
const obj = {};
obj.projectName = project.name;
obj.build = project.runs[0].build;
projects.push(obj);
});
});
});
envTable = projects
return (
<>
<div>ENVIRONMENT</div>
<table>
<thead>
<tr>
{headerTable && headerTable.map
((header, indx) => {
return (<th key={indx}>{header}</th>)
})}
</tr>
</thead>
<tbody>
{envTable && envTable.length > 0 && envTable.map
((row, indx) => {
return (<tr key={indx}>
<td>{row.projectName}</td>
<td>{row.build}</td>
</tr>)
})}
</tbody>
</table>
</>
)
}
Now, i am trying to do a group by environment
and then display the projects for each environment. i am expecting my final result to be something like this shown in image below.
Can someone please let me know what changes i have to do in order to show the group by table form for my data.
CodePudding user response:
You're actually quite close: all you need is to actually create a dictionary where you have key-value pairs where the key is the environment and the value is simply the array of projects associated with that environment. If we slightly repurpose your forEach
logic to use Array.prototype.reduce
, we can get the structure you want:
const projectsByEnv = envResponse.reduce((acc, envMetric) => {
const { environment, verticals } = envMetric;
const projects = verticals.flatMap((vertical) => {
return vertical.projects.map((project) => {
return {
projectName: project.name,
build: project.runs[0].build
};
});
});
if (acc[environment]) {
acc[environment].push(...projects);
} else {
acc[environment] = projects;
}
return acc;
}, {});
The projectsByEnv
will simply have the following format: {PROJECT 1: Array(1), PROJECT 2: Array(2)}
. To output it in your template, we need to step through the object using Object.entries()
, and use the colspan trick to ensure the environment spans two columns:
<tbody>
{Object.entries(projectsByEnv).map(([environment, projects]) => {
return (
<>
<tr>
<td colspan="2">{environment}</td>
</tr>
{projects.map((project) => {
return (
<tr>
<td>{project.projectName}</td>
<td>{project.build}</td>
</tr>
);
})}
</>
);
})}
</tbody>
With a bit of a CSS trick as well:
td[colspan] {
border-top: 1px dashed black;
border-bottom: 1px dashed black;
}
This is how it looks like after making the above changes:
You can see the full proof-of-concept example on CodeSandbox: