React treeview from JSON array

Viewed 8344

I am making a treeview from JSON using react. So far I have made a collapsible tree using this example data:

var data = {
      title: "Node 1",
      childNodes: [
        {title: "Childnode 1.1"},
        {title: "Childnode 1.2",
          childNodes: [
            {title: "Childnode 1.2.1",
              childNodes: [
                {title: "Childnode 1.2.1.1"}
              ]}, {title: "Childnode 1.2.2"}
          ]}
      ]
    };

But this is one object. I want to get JSON array of objects as input and generate treeview from that but I am unable to understand where to change the code.

Here's my render function:

render() {
    var childNodes;

    if (this.props.node.childNodes != null) {
      childNodes = this.props.node.childNodes.map(function (node, index) {
        return <li key={index}><Treeview node={node}/></li>
      });
    }

    return (
      <form>
        <div>
          <input type="checkbox"/>
          <label for>{this.props.node.title}</label>
        </div>
        <ul>
          {childNodes}
        </ul>
      </form>

    );
  }

How can I change the code to work with the whole array and not just one object?

3 Answers

Recursion is fun!

const data = [{
  title: "Node 1",
  childNodes: [
    { title: "Childnode 1.1" },
    {
      title: "Childnode 1.2",
      childNodes: [
        {
          title: "Childnode 1.2.1",
          childNodes: [
            { title: "Childnode 1.2.1.1" }
          ]
        }, { title: "Childnode 1.2.2" }
      ]
    }
  ]
}];

const App = () => (
  <form>
    <Tree data={data} />
  </form>
);

const Tree = ({data}) => ( 
  <ul>
    {data && data.map(item => (
      <li>
        {item.title}
        {item.childNodes && <Tree data={item.childNodes} />}
      </li>
    ))}
  </ul>
);

Demo: https://codesandbox.io/s/01kl2xmo40

This example below can work on all json objects i have tested it on checkout my github repo: https://github.com/nickjohngray/blockout/blob/master/src/Tree/Tree.tsx the html generated is the same as https://www.w3schools.com/howto/howto_js_treeview.asp

class Tree extends React.Component {

   

    processObject = (object) =>
        Object.keys(object).map((key, reactKey) => {
            return (
                <li key={reactKey + key}>
                    {this.buildNode(key)}
                    <ul className="nested">
                        {this.isPrimative(object[key]) ? this.buildLeaf(object[key]) :
                            this.isArray(object[key]) ? this.loopArray(object[key]) : this.processObject(object[key])}
                    </ul>
                </li>
            )
        })

    loopArray = (array) =>
        array.map((value, key) =>
            <div key={key + value}>
                {this.isPrimative(value) ? this.buildLeaf(value) :
                    this.isArray(value) ? this.loopArray(value) : this.processObject(value)}
            </div>
        )

    isArray = (value) =>
        Array.isArray(value)

    isPrimative = (value) => {
        return typeof (value) === 'string'
            || typeof (value) === 'number'
            || typeof (value) === 'boolean'
    }

    buildNode = (key: string) =>
        <span className="node"
              onClick={
                  (e) => {
                      this.toggle(e)
                  }}>
             {key}
            </span>

    buildLeaf = (value: string) =>
        <li className="leaf"
            onClick={
                (e) => {

                }}>
            {value}
        </li>

    toggle = (event) => {
        event.target.parentElement.querySelector(".nested").classList.toggle("active");
        event.target.classList.toggle("node-down");
    }

    render = () => <>
        <ul id="myUL">
            {this.processObject(json)}
        </ul>
    </>
}

export default Tree;

this is the css for it, copied from wc3 schools

/* Remove default bullets */
ul, #myUL {
    list-style-type: none;
}

body {
    background: red;
}


/* Remove margins and padding from the parent ul */
#myUL {
    margin: 0;
    padding: 0;
}

/* Style the caret/arrow */
.caret {
    cursor: pointer;
    user-select: none; /* Prevent text selection */
    background: red;
}

/* Create the caret/arrow with a unicode, and style it */
.caret::before {
    content: "\25B6";
    color: black;
    display: inline-block;
    margin-right: 6px;
}

/* Rotate the caret/arrow icon when clicked on (using JavaScript) */
.caret-down::before {
    transform: rotate(90deg);
}

/* Hide the nested list */
.nested {
    display: none;
}

/* Show the nested list when the user clicks on the caret/arrow (with JavaScript) */
.active {
    display: block;
}

I was also searching for a similar feature. developed a fully customizable lightweight tree generator component.

You can pass custom child and parent components for a better view

helpful for users who are searching for the same.

https://www.npmjs.com/package/react-custom-tree

Related