Reputation: 213
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
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));
}
Upvotes: 1