React Help: On Link Click, how to expand all and collapse all tree nodes using React?
Tags: react
Published: 2022-04-14 00:05:34

I generate a tree from xml file using react. I have two links Expand All and Collapse All. How to expand all tree nodes if tree is in Collapse Mode when Expand All link will click? How to Collapse all tree nodes if tree is in Expand Mode when Collapse All link will be clicked?

```
App.js
import React, { Component } from 'react';
import { Switch, Route, Link } from "react-router-dom";
import { BrowserRouter } from 'react-router-dom';
import Home from './Home';

export class App extends Component {
  constructor(props) {
    super(props);
  }

render() {
    return (
        <BrowserRouter>
            <Switch>
{/* Otherwise, render the Landing component */}
                <Route component={Home} />
            </Switch>
        </BrowserRouter>
    );
}
}

export default App;
-------------------------------

Home.js

import React, { Component } from 'react';
import ProductsTree from './ProductsTreeView';

class Home extends React.Component {
    constructor(props) {
        super(props);
this.state =
        {
currentNode: {},
        };
        this.setCurrentNode = this.setCurrentNode.bind(this);
    }

    setCurrentNode(node) {
        this.setState({ currentNode: node });
    }
    
    render() {
        return (
<div>
                    <table width="100%" border="0" cellSpacing="0" cellPadding="0">
                        <tbody>
                            <tr width="100%">
                                <td align="left" nowrap="true">
<b><a href=’’>Expand All</a></b>
<b><a href=’’>Collapse All</a></b>
    </td>
                            </tr>
                        </tbody>
                    </table>
                    <br />
                    <ProductsTree setCurrentNode={this.setCurrentNode} />
</div>

);
    }
}

export default Home;

-------------------------------

ProductsTreeView.js

import React, { Component } from 'react';
import axios from 'axios';
import XMLParser from 'react-xml-parser';
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'];
     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) })
            );
    }

    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) {
        if (node.nodes.length === 0) return;
        this.props.setCurrentNode(node);

        function _toggleNode(currentNode, node) {
            if (currentNode.id === node.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 acitveChildren = null;
        if (node.isActive && node.nodes.length > 0) {
            acitveChildren = (
                <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);
                }}
            >
                {node.description} - {node.key_id} - {node.linkpagename}
                {acitveChildren}
            </li>
        );
    }
}

export default ProductsTreeView;

---------------------------------------
tree.xml
<?xml version="1.0" standalone="yes"?>
<tree>
    <entity id="e11" key-id="1" link-page-name="Add_Item">
        <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="Add_SubItem">
            <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_SubItem">
                <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_ItemTemplate">
                    <description>A_Test_Template</description>
                    <image>images/paper.gif</image>
                    <imageOpen>images/paper.gif</imageOpen>
                </entity>
            </entity>
        </entity>
        <entity id="e21" key-id="1" link-page-name="Add_SubItem">
            <description>Checking</description>
            <image>images/plus.gif</image>
            <imageNode>images/de.gif</imageNode>
            <imageOpen>images/minus.gif</imageOpen>
            <entity id="e3606" key-id="606" link-page-name="Edit_SubItem">
                <description>Categories</description>
                <image>images/plus.gif</image>
                <imageNode>images/de.gif</imageNode>
                <imageOpen>images/minus.gif</imageOpen>
                <entity id="e45112" key-id="5112" link-page-name="Edit_ItemTemplate">
                    <description>All states</description>
                    <image>images/paper.gif</image>
                    <imageOpen>images/paper.gif</imageOpen>
                </entity>
            </entity>
            <entity id="e3382" key-id="382" link-page-name="Edit_SubItem">
                <description>Advan</description>
                <image>images/plus.gif</image>
                <imageNode>images/de.gif</imageNode>
                <imageOpen>images/minus.gif</imageOpen>
                <entity id="e43157" key-id="3157" link-page-name="Edit_ItemTemplate">
                    <description>States</description>
                    <image>images/paper.gif</image>
                    <imageOpen>images/paper.gif</imageOpen>
                </entity>
            </entity>
            <entity id="e247" key-id="47" link-page-name="Add_SubItem">
                <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_SubItem">
                    <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_ItemTemplate">
                        <description>temp1</description>
                        <image>images/paper.gif</image>
                        <imageOpen>images/paper.gif</imageOpen>
                    </entity>
                </entity>
            </entity>

        </entity>
    </entity>
    <entity id="e12" key-id="2" link-page-name="Add_Item">
        <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="Add_SubItem">
            <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_SubItem">
                <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_ItemTemplate">
                    <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_SubItem">
                <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_ItemTemplate">
                    <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="Add_SubItem">
            <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_SubItem">
                <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_ItemTemplate">
                    <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_SubItem">
                <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_ItemTemplate">
                    <description>gggggg</description>
                    <image>images/paper.gif</image>
                    <imageOpen>images/paper.gif</imageOpen>
                </entity>
        </entity>
        </entity>       

    </entity>
</tree>
```