TestUser
TestUser

Reputation: 213

React: How to collapse all the all open children nodes if their parent node is closing?

enter image description here I am using react. I am able to generate a tree from xml file.
Please find my sandbox: https://codesandbox.io/s/shy-snow-nfce4i Please find the attached image. The code is working fine in Visual Studio. I am not sure how to use sandbox, not able to understand sandbox error.

Currently, tree is working fine. Collapse/Minimize of the expanded/open children nodes are not working if their parent node is collapsing.

Please check my code and see where the code needs change.

Thanks a lot.

import React, { Component } from "react";
import ProductsTree from "./ProductsTreeView";
const initialState = {
  currentNode: {},
  data: ""
};
export class App extends Component {
  constructor(props) {
    super(props);
    this.state = initialState;
    this.setCurrentNode = this.setCurrentNode.bind(this);
  }
  setCurrentNode(node) {
    this.setState({ currentNode: node });
  }
  render() {
    return (
      <div>
        <ProductsTree setCurrentNode={this.setCurrentNode} />
      </div>
    );
  }
}
export default App;
______________________________________________________
import React, { Component } from "react";
import axios from "axios";
import XMLParser from "react-xml-parser";
import { Link } from "react-router-dom";
import tree from "./tree.xml";
class ProductsTreeView extends Component {
  render() {
    return (
      <div id="TreeView">
        <TreeView setCurrentNode={this.props.setCurrentNode} />
      </div>
    );
  }
}

class Node {
  description = "n/a";
  id = -1;
  key_id = -1;
  linkpagename = "";
  isActive = false;
  nodes = [];
  constructor(description, id, key_id, linkpagename) {
    this.description = description;
    this.id = id;
    this.key_id = key_id;
    this.linkpagename = linkpagename;
  }

  static nodesFromXml(xml) {
    const map = (entity, nodes) => {
      const id = entity.attributes["id"];
      const key_id = entity.attributes["key-id"];
      const descriptionText =
        entity.children[
          entity.children.findIndex((child) => child.name === "description")
        ].value;
      const entities = entity.children.filter(
        (child) => child.name === "entity"
      );

      var linkPageName = entity.attributes["link-page-name"];
      linkPageName = linkPageName.replace(".aspx", "");
      const node = new Node(descriptionText, id, key_id, linkPageName);
      nodes.push(node);
      entities.forEach((entity) => map(entity, node.nodes));
    };
    const parsedData = new XMLParser().parseFromString(xml);
    const entities = parsedData.children.filter(
      (child) => child.name === "entity"
    );

    const nodes = [];
    entities.forEach((entity) => map(entity, nodes));
    return nodes;
  }
}

class TreeView extends React.Component {
  constructor(props) {
    super(props);
    this.state = { nodes: [] };
    this.toggleNode = this.toggleNode.bind(this);
  }
  componentDidMount() {
    axios
      .get(tree, { "Content-Type": "application/xml; charset=utf-8" })
      .then((response) =>
        this.setState({ nodes: Node.nodesFromXml(response.data) })
      )
      .catch((error) => console.error("Error:", error));
  }
  render() {
    const nodes = this.state.nodes
    return (
      <ul>
        {nodes.map((node) => (
          <TreeNode
            id={node.id}
            key={node.key_id}
            node={node}
            onToggle={this.toggleNode}
            setCurrentNode={this.props.setCurrentNode}
          />
        ))}
      </ul>
    );
  }
  toggleNode(node) {
    this.props.setCurrentNode(node);
    function _toggleNode(currentNode, node) {
      if (currentNode.id === node.id) {
        //currentNode.id === node.id)

        {
          if (currentNode.key_id === node.key_id) {
            currentNode.isActive = !currentNode.isActive;
          }
        }
      } else {
        currentNode.nodes.forEach((childNode) => _toggleNode(childNode, node));
      }
    }
    const nodes = this.state.nodes;
    nodes.forEach((currentNode) => _toggleNode(currentNode, node));
    this.setState((state) => (state.nodes = nodes));
  }
}
class TreeNode extends React.Component {
  render() {
    const node = this.props.node;
    const onToggle = this.props.onToggle;
    let activeChildren = null;
    if (node.isActive && node.nodes.length > 0) {
      activeChildren = (
        <ul>
          {node.nodes.map((node) => (
            <TreeNode
              id={node.id}
              key={node.key_id}
              node={node}
              onToggle={onToggle}
            />
          ))}
        </ul>
      );
    }

    return (
      <li
        id={node.id}
        linkpagename={node.linkpagename}
        key={node.key_id}
        onClick={(event) => {
          event.stopPropagation();
          onToggle(node);
        }}
      >
        <Link
          to={node.linkpagename}
          style={{ textDecoration: "none", color: "#000000" }}
        >[![enter image description here][3]][3]
          {node.description}
        </Link>{" "}
        - {node.key_id} - {node.linkpagename}
        {activeChildren}
      </li>
    );
  }
}
export default ProductsTreeView;

<?xml version="1.0" standalone="yes"?>
<tree>
       <entity id="e11" key-id="1" link-page-name="Add_Category">
              <description>Service</description>
              <image>images/plus.gif</image>
              <imageNode>images/de.gif</imageNode>
              <imageOpen>images/minus.gif</imageOpen>
              <entity id="e248" key-id="48" link-page-name="Edit_Category">
                     <description>A_test1_test1</description>
                     <image>images/plus.gif</image>
                     <imageNode>images/de.gif</imageNode>
                     <imageOpen>images/minus.gif</imageOpen>
                     <entity id="e3717" key-id="717" link-page-name="Edit_Product">
                           <description>A_SubItem1</description>
                           <image>images/plus.gif</image>
                           <imageNode>images/de.gif</imageNode>
                           <imageOpen>images/minus.gif</imageOpen>
                           <entity id="e45546" key-id="5546" link-page-name="Edit_ProdTemplate">
                                  <description>A_Test_Template</description>
                                  <image>images/paper.gif</image>
                                  <imageOpen>images/paper.gif</imageOpen>
                           </entity>
                     </entity>
              </entity>
              <entity id="e247" key-id="47" link-page-name="Edit_Category">
                     <description>A_test6</description>
                     <image>images/plus.gif</image>
                     <imageNode>images/de.gif</imageNode>
                     <imageOpen>images/minus.gif</imageOpen>
                     <entity id="e3716" key-id="716" link-page-name="Edit_Product">
                           <description>A_Item</description>
                           <image>images/plus.gif</image>
                           <imageNode>images/de.gif</imageNode>
                           <imageOpen>images/minus.gif</imageOpen>
                           <entity id="e45545" key-id="5545" link-page-name="Edit_ProdTemplate">
                                  <description>temp1</description>
                                  <image>images/paper.gif</image>

                                  <imageOpen>images/paper.gif</imageOpen>
                           </entity>
                     </entity>
              </entity>
       </entity>

       <entity id="e12" key-id="2" link-page-name="Add_Category">

              <description>Sales</description>

              <image>images/plus.gif</image>

              <imageNode>images/de.gif</imageNode>

              <imageOpen>images/minus.gif</imageOpen>

              <entity id="e230" key-id="30" link-page-name="Edit_Category">

                     <description>Gift Cards</description>

                     <image>images/plus.gif</image>

                     <imageNode>images/de.gif</imageNode>

                     <imageOpen>images/minus.gif</imageOpen>

                     <entity id="e3421" key-id="421" link-page-name="Edit_Product">

                           <description>Sample Card</description>

                           <image>images/plus.gif</image>

                           <imageNode>images/de.gif</imageNode>

                           <imageOpen>images/minus.gif</imageOpen>

                           <entity id="e43308" key-id="3308" link-page-name="Edit_ProdTemplate">

                                  <description>greeting temp</description>

                                  <image>images/paper.gif</image>

                                  <imageOpen>images/paper.gif</imageOpen>

                           </entity>

                     </entity>

                     <entity id="e3422" key-id="422" link-page-name="Edit_Product">

                           <description>De Card</description>

                           <image>images/plus.gif</image>

                           <imageNode>images/de.gif</imageNode>

                           <imageOpen>images/minus.gif</imageOpen>

                           <entity id="e43309" key-id="3309" link-page-name="Edit_ProdTemplate">

                                  <description>NS Temp</description>

                                  <image>images/paper.gif</image>

                                  <imageOpen>images/paper.gif</imageOpen>

                           </entity>

                     </entity>

 

              </entity>

              <entity id="e215" key-id="15" link-page-name="Edit_Category">

                     <description>Chck</description>

                     <image>images/plus.gif</image>

                     <imageNode>images/de.gif</imageNode>

                     <imageOpen>images/minus.gif</imageOpen>

                     <entity id="e3671" key-id="671" link-page-name="Edit_Product">

                           <description>Add item</description>

                           <image>images/plus.gif</image>

                           <imageNode>images/de.gif</imageNode>

                           <imageOpen>images/minus.gif</imageOpen>

                           <entity id="e45438" key-id="5438" link-page-name="Edit_ProdTemplate">

                                  <description>Ahhhh</description>

                                  <image>images/paper.gif</image>

                                  <imageOpen>images/paper.gif</imageOpen>

                           </entity>

                     </entity>

                     <entity id="e3450" key-id="450" link-page-name="Edit_Product">

                           <description>Advtttt</description>

                           <image>images/plus.gif</image>

                           <imageNode>images/de.gif</imageNode>

                           <imageOpen>images/minus.gif</imageOpen>

                           <entity id="e43577" key-id="3577" link-page-name="Edit_ProdTemplate">

                                  <description>gggggg</description>

                                  <image>images/paper.gif</image>

                                  <imageOpen>images/paper.gif</imageOpen>

                           </entity>

                     </entity>

              </entity>

 

       </entity>

</tree>

Upvotes: 1

Views: 1102

Answers (1)

Drew Reese
Drew Reese

Reputation: 203208

Update the toggleNode handler's internal _toggleNode function to take a third parameter, we'll call it isActive that if set to any non-undefined value will set the current node's isActive property to that value, otherwise do the normal node toggling. Add an additional check that if the node was just toggled inactive to recurse on that node's subtree and pass an isActive value of false to deactivate all nodes in that subtree.

toggleNode(node) {
  const { nodes } = this.state;
  this.props.setCurrentNode(node);

  function _toggleNode(currentNode, node, isActive) {
    if (isActive !== undefined) {
      currentNode.isActive = isActive;
    } else if (currentNode.id === node.id) {
      if (currentNode.key_id === node.key_id) {
        currentNode.isActive = !currentNode.isActive;
      }
    }
    currentNode.nodes.forEach((childNode) =>
      _toggleNode(childNode, node, currentNode.isActive ? undefined : false)
    );
  }

  nodes.forEach((currentNode) => _toggleNode(currentNode, node));

  this.setState((state) => (state.nodes = nodes));
}

Edit react-how-to-collapse-all-the-all-open-children-nodes-if-their-parent-node-is-c

Upvotes: 1

Related Questions