1

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?

5
  • Have you tried mapping only the items from the object that you want? i.e. doing something like this in your render function. data.map((element) => { if(element.id in listOfItemsRequired){ return element; } }) Commented Apr 28, 2022 at 4:41
  • @SampurnG all items are required. Item will be unnecessary when it rendered already. Commented Apr 28, 2022 at 4:54
  • So you don't want to display the items which are at level 2 right? Commented Apr 28, 2022 at 5:01
  • I want to display all items, but once. Example: SMT and QC are level=1. And Tester and Operator are level=2, child of level=1 QC. And they already rendered under QC. What I want, they should not be rendered again under Mhz, level=0 Commented Apr 28, 2022 at 5:09
  • 1
    Okay got it, wait I'll post a code sandbox which will be similar to the given documentation. As per my understanding, the data object that you've created, needs to be modified. Commented Apr 28, 2022 at 7:07

2 Answers 2

1

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)
  }))
Sign up to request clarification or add additional context in comments.

Comments

1

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"
        }
      ]
    }
  ]
};

7 Comments

Yes I've already done with that. But I want to fill that with my own array. Anyway, okay, how can I change my array to desired json data wich required by mui treeview?
Just check the files in the code sandbox(Demo.tsx), I've edited it, you can try something similar, If this helped you can accept it as an answer and close this thread
I've added the data json to my answer, I'm sorry but you'll have to be more clear, i cannot understand what you mean. It is already a JSON object, what else should i convert it in?
data comes from API, as you see it's not in desired format as required by mui tree. So we have to option, filling the tree with some kind of logic or making this data to desired format
Oh okay i got it, for that it would be fairly simple, but it will take a little time and it'll be fairly lengthy. I'd recommend you to do this yourself as it is a good exercise to familiarise yourself with array traversals. Also breaking down your hierarchyId into an array would simplify things a lot more. I'll try to post a solution once i get off work.
|

Your Answer

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.