I'm using treeview to display my hierarchical data.
I have following array of objects:
const data = [
{ id: 1, hierarchyid: "/", level: 0, name: "Mhz" },
{ id: 2, hierarchyid: "/2/", level: 1, name: "SMT" },
{ id: 3, hierarchyid: "/3/", level: 1, name: "QC" },
{ id: 4, hierarchyid: "/3/4/", level: 2, name: "Tester" },
{ id: 5, hierarchyid: "/3/5/", level: 2, name: "Operator" },
];
I need to fill my treeview with this data. What I did so far:
getTreeItems(node, nodes) {
const filtered = nodes.filter(
(n) => n.hierarchyid.includes(node.hierarchyid) && n.level != node.level
);
return (
<TreeItem
key={node.id}
nodeId={node.hierarchyid}
label={node.name}
onClick={() => onClicked(node)}
>
{filtered.length > 0
? filtered.map((node) => this.getTreeItems(node, filtered))
: null}
</TreeItem>
);
}
And rendering:
render() {
// The data comes from Server
const data = [
{ id: 1, hierarchyid: "/", level: 0, name: "Mhz" },
{ id: 2, hierarchyid: "/2/", level: 1, name: "SMT" },
{ id: 3, hierarchyid: "/3/", level: 1, name: "QC" },
{ id: 4, hierarchyid: "/3/4/", level: 2, name: "Tester" },
{ id: 5, hierarchyid: "/3/5/", level: 2, name: "Operator" },
];
return (
<TreeView
aria-label="file system navigator"
defaultCollapseIcon={<ExpandMoreIcon />}
defaultExpandIcon={<ChevronRightIcon />}
sx={{ height: "auto", flexGrow: 1, width: "auto", overflowY: "auto" }}
>
{this.getTreeItems(
{ id: 1, hierarchyid: "/", level: 0, name: "Mhz" },
data
)}
</TreeView>
);
}
}
This giving me view like:
Mhz
SMT
QC
Tester
Operator
Tester // they shouldn't be displayed
Operator // they have already rendered as child under QC
My problem is can not exclude already rendered nodes.
Update
MUI TreeView supports special JSON
data for its nodes. So converting array
to JSON
also solves the problem. Something like that:
const data = {
id: 1,
hierarchyid: "/",
level: 0,
name: "Mhz",
children: [
{
id: 2,
hierarchyid: "/2/",
level: 1,
name: "SMT"
},
{
id: 3,
hierarchyid: "/3/",
level: 1,
name: "QC",
children: [
{
id: 4,
hierarchyid: "/3/4/",
level: 2,
name: "Tester"
},
{
id: 5,
hierarchyid: "/3/5/",
level: 2,
name: "Operator"
}
]
}
]
};
the array of objects came from Server, so how can I make this Json from array data?
CodePudding user response:
If we write a quick function to test whether one hierarchy id is the direct descendant of another, then we can use it to write a simple recursive version:
const isChild = (prefix) => ({hierarchyid}) =>
hierarchyid .startsWith (prefix)
&& /^[^\/]*\/$/ .test (hierarchyid .slice (prefix .length))
const nest = (xs, prefix = '') =>
xs .filter (isChild (prefix)) .map ((x, _, __, children = nest (xs, x .hierarchyid)) => ({
...x,
... (children .length ? {children} : {})
}))
const data = [{id: 1, hierarchyid: "/", level: 0, name: "Mhz"}, {id: 2, hierarchyid: "/2/", level: 1, name: "SMT"}, {id: 3, hierarchyid: "/3/", level: 1, name: "QC"}, {id: 4, hierarchyid: "/3/4/", level: 2, name: "Tester"}, {id: 5, hierarchyid: "/3/5/", level: 2, name: "Operator"}]
console .log (nest (data))
.as-console-wrapper {max-height: 100% !important; top: 0}
isChild
checks whether the hierarchy id starts with our prefix and if the remainder has only one '/'
, at the very end.
nest
is not as efficient as it might be, as it scans the whole array for each node. But I wouldn't worry about it until I had tens of thousands of entries.
If you don't mind having some empty children
arrays on your leaves, it's simpler still:
const nest = (xs, prefix = '') =>
xs .filter (isChild (prefix)) .map ((x) => ({
...x,
children: nest (xs, x .hierarchyid)
}))
CodePudding user response:
SO I've looked at the documentation and they've clearly mentioned a way to design your data object in such a way so that the hierarchy can be shown without multiple nodes repeating.
Try going through this once and change your render functions according to the documentation, you can probably get your desired result.
const data: RenderTree = {
id: "root",
name: "Mhz",
children: [
{
id: "1",
name: "SMT"
},
{
id: "3",
name: "QZ",
children: [
{
id: "4",
name: "Tester"
},
{
id: "4",
name: "Operator"
}
]
}
]
};