Issue
Let's say I have a nested JSON object variable like:
{
"A":{
"a": [1,2],
"b": [3]
},
"B":{
"c":[4],
}
}
And I want it to be displayed in relative-sized tabular form like:
I have considered several methods and I found that every each method has some trick points to display in even table format.
Since each side of the cells must have the same length as its adjacent cell in both row and column directions, using div tag must be very tricky without absolute size. Even without that table head part, I think it won't be easy to match each side between "A" part and "B" part in the example picture.
So, I guess using table tag might be the best choice. But using table will require destructuring all objects and complicated illegible additional code for calculating each row span, which is super non-declarative and degrades the readability significantly.
Is there any better alternative way to display nested object in tabular format with relative sizes in React, HTML?
Solution
Below is my attempt at this problem with recursion to fill the cell rowSpan at each level
import React from "react";
// Rearranged consistent data format
const data = [
{
label: "A",
children: [
{ label: "a", children: [{ label: "1" }, { label: "2" }] },
{ label: "b", children: [{ label: "3" }] },
],
},
{
label: "B",
children: [{ label: "c", children: [{ label: "4" }] }],
},
];
// Traverse each level recursively to find the rowSpan for each cell and rearranging to column data
const traverse = (nodes, results, depth = 0) => {
let counter = 0;
if (!results[depth]) results[depth] = [];
const result = results[depth];
for (let node of nodes) {
// Each cell rowSpan will be the sum of all children's rowSpan
node.height = node.children
? traverse(node.children, results, depth + 1)
: 1;
counter += node.height;
result.push(node);
// Pushing null to cover rowSpan space
for (var i = 0; i < node.height - 1; i++) {
result.push(null);
}
}
return counter;
};
const results = [];
traverse(data, results);
const Table = () => {
// Results is arranged based on column, but the rendering is per row
// We have to invert the 2d index
let content = [];
for (let i = 0; i < results[0].length; i++) {
let innerContent = [];
for (let j = 0; j < results.length; j++) {
let cell = results[j][i];
innerContent.push(
!cell ? null : (
<th key={j} rowSpan={cell.height}>
{cell.label}
</th>
)
);
}
content.push(<tr key={i}>{innerContent}</tr>);
}
return <table>{content}</table>;
};
export default Table;
Answered By - Harry Hsu
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.