If statement & PopUp window in React

Click For Summary
The discussion focuses on implementing a popup in React that appears when a specific radio button option is selected. The user initially struggles with using an if statement and defining the popup correctly, leading to confusion between popups and modal dialogs. Suggestions include using Material UI components for better functionality and styling, as well as ensuring the correct JavaScript or TypeScript version is used in the code. The conversation also touches on connecting React with a FastAPI backend to handle form submissions, emphasizing the importance of separating business logic from presentation. Overall, the thread provides insights into managing user interactions and component behavior in React applications.
  • #31
I had tried the following :

JavaScript:
   const [dataObj, setDataObj] = useState([]); 
 
   useEffect(() => {
        fetch('https://giant-db-connection.onrender.com/opc_ua_tree/')
            .then((res) => res.json())
            .then((data) => {
                setDataObj(data[0]['tree_structure'][0].Nodes[0]);
                console.log(dataObj.DisplayName);
                while (dataObj.Nodes) {
                    for (let i = 0; i < dataObj.Nodes.length; i++) {
                        console.log(dataObj.Nodes[i].DisplayName);
                    }
                    setDataObj(dataObj.Nodes);
                }
            });
    }, []);
I want to display all the DisplayNames. First I did it with many for loops and it worked, now I am trying to write it with less code by setting dataObj.Nodes into the current dataObj. Is this correct so far?

Can the result be also in a TreeView (TreeItem) ? 🤔
 
Technology news on Phys.org
  • #32
mathmari said:
I want to display all the DisplayNames. First I did it with many for loops and it worked, now I am trying to write it with less code by setting dataObj.Nodes into the current dataObj. Is this correct so far?
I wouldn't do it that way. Either the date in the tree is static, in which case there is no point in using a reactive object for it, or it is dynamic in which case you don't want to be managing it inside a component - it should be in a Redux store.

mathmari said:
Can the result be also in a TreeView (TreeItem) ?
Of course, see the example at https://mui.com/material-ui/react-tree-view/#rich-object. You may want to pre-parse the data into a much more normalized format.
 
  • #33
pbuk said:
I wouldn't do it that way. Either the date in the tree is static, in which case there is no point in using a reactive object for it, or it is dynamic in which case you don't want to be managing it inside a component - it should be in a Redux store.

Could you explain that further to me? Do we have to store the data instead of dataObj in a Redux store? 🤔
 
  • #34
So we save teh whole tree in a Redux store and then we we get the component that we want to print with useSelector ? 🤔
 
  • #35
Well I'd be inclined to flatten the tree in the response into an object with the id as the key:
JavaScript:
{
  'id-1234': {
    title: '...',
    children: [
      'id-2345',
      'id-9876',
    ],
  },
  'id-2345': {
    // ...
  },
  // ...
}
which will make it much easier to use, but otherwise, yes.
 
  • Like
Likes mathmari
  • #36
pbuk said:
Well I'd be inclined to flatten the tree in the response into an object with the id as the key:
JavaScript:
{
  'id-1234': {
    title: '...',
    children: [
      'id-2345',
      'id-9876',
    ],
  },
  'id-2345': {
    // ...
  },
  // ...
}
which will make it much easier to use, but otherwise, yes.

I haven't understood what you mean. Could you explain that further to me?
 
  • #37
Do you mean how to store the tree in a redux tree or what do you mean by the above?
 
  • #38
mathmari said:
I haven't understood what you mean. Could you explain that further to me?
Well here is the beginning of the response:
JavaScript:
[
  {
    "tree_structure": [
      {
        "TypeDefinition": "Namespace",
        "IndexName": "0:Objects",
        "URI": "http://opcfoundation.org/UA/",
        "Nodes": [
          {
            "DisplayName": "Objects",
            "Attributes": [
              {
                "NodeId": "i=85",
                "NodeClass": "Object",
                "BrowseName": "Objects",
                "DisplayName": "Objects",
                "Description": null,
                "WriteMask": null,
                "UserWriteMask": null,
                "EventNotifier": null
              }
            ],
            "Nodes": [
              {
                "DisplayName": "Server",
                "Attributes": [
                  {
                    "NodeId": "i=2253",
                    "NodeClass": "Object",
                    "BrowseName": "Server",
                    "DisplayName": "Server",
                    "Description": null,
                    "WriteMask": null,
                    "UserWriteMask": null,
                    "EventNotifier": ["SubscribeToEvents"]
                  }
                ],
                "Nodes": [
                  {
                    "DisplayName": "ServerStatus",
                    "Attributes": [
                      {
                        "NodeId": "i=2256",
                        "NodeClass": "Variable",
                        "BrowseName": "ServerStatus",
                        "DisplayName": "ServerStatus",
                        "Description": null,
                        "WriteMask": null,
                        "UserWriteMask": null,
                        "Value": "ServerStatusDataType(StartTime=datetime.datetime(2022, 9, 27, 7, 45, 53, 181000), CurrentTime=datetime.datetime(2022, 9, 27, 14, 57, 5, 827000), State=<ServerState.Running: 0>, BuildInfo_=BuildInfo(ProductUri='urn:prosysopc.com:OPCUA:SimulationServer', ManufacturerName='Prosys OPC Ltd.', ProductName='SimulationServer@DESKTOP-VN3GQ4Q', SoftwareVersion='5.3.0', BuildNumber='64', BuildDate=datetime.datetime(1970, 1, 1, 0, 0)), SecondsTillShutdown=0, ShutdownReason=LocalizedText(Locale='', Text=''))",
                        "DataType": "ExtensionObject",
                        "ValueRank": "Scalar",
                        "AccessLevel": ["CurrentRead"],
                        "UserAccessLevel": ["CurrentRead"],
                        "MinimumSamplingInterval": 1000.0,
                        "Historizing": false
                      }
                    ],
Let's say you want to display the minumum sampling interval for the node with id "i=2256": this is not going to be easy. If instead you parse this tree into a flat structure:
JavaScript:
{
  "tree_structure": {
    "TypeDefinition": "Namespace",
    "IndexName": "0:Objects",
    "URI": "http://opcfoundation.org/UA/",
    // Note the change from an array to a POJO.
    "Nodes": {
      "i=85" : {
        "DisplayName": "Objects",
        "Attributes": [
          {
            "NodeId": "i=85",
            "NodeClass": "Object",
            "BrowseName": "Objects",
            "DisplayName": "Objects",
            "Description": null,
            "WriteMask": null,
            "UserWriteMask": null,
            "EventNotifier": null
          },
        ],
        parent: null,
        children: [
          "i=2253",
        ],
      },

      "i-2253": {
        "DisplayName": "Server",
        "Attributes": [
          {
            "NodeId": "i=2253",
            "NodeClass": "Object",
            "BrowseName": "Server",
            "DisplayName": "Server",
            "Description": null,
            "WriteMask": null,
            "UserWriteMask": null,
            "EventNotifier": ["SubscribeToEvents"]
          }
        ],
        parent: "i=85",
        children: [
          "i=2256",
        ],
      },

      "i=2256": {
        "DisplayName": "ServerStatus",
        "Attributes": [
          {
            "NodeId": "i=2256",
            "NodeClass": "Variable",
            "BrowseName": "ServerStatus",
            "DisplayName": "ServerStatus",
            "Description": null,
            "WriteMask": null,
            "UserWriteMask": null,
            "Value": "ServerStatusDataType(StartTime=datetime.datetime(2022, 9, 27, 7, 45, 53, 181000), CurrentTime=datetime.datetime(2022, 9, 27, 14, 57, 5, 827000), State=<ServerState.Running: 0>, BuildInfo_=BuildInfo(ProductUri='urn:prosysopc.com:OPCUA:SimulationServer', ManufacturerName='Prosys OPC Ltd.', ProductName='SimulationServer@DESKTOP-VN3GQ4Q', SoftwareVersion='5.3.0', BuildNumber='64', BuildDate=datetime.datetime(1970, 1, 1, 0, 0)), SecondsTillShutdown=0, ShutdownReason=LocalizedText(Locale='', Text=''))",
            "DataType": "ExtensionObject",
            "ValueRank": "Scalar",
            "AccessLevel": ["CurrentRead"],
            "UserAccessLevel": ["CurrentRead"],
            "MinimumSamplingInterval": 1000.0,
            "Historizing": false
          }
        ],
        parent: "i=2253",
        children: [
          // ...
        ],
      },
      // More nodes.
it's going to be much easier, it's just data.tree_structure.Nodes['i=2253'].Attributes[0].MinimumSamplingInterval
 
  • Like
Likes mathmari
  • #39
And using the redux store this is possible?
 
  • #40
For the beginning I tried to do that with a non elegant way, to get all data by for loops, I used 3 for loops. I am not reallt sure if I print it correctly with the <TreeView>, could you take a look at it ?

JavaScript:
    const [dataObj, setDataObj] = useState([]);
    
    useEffect(() => {
        fetch('https://giant-db-connection.onrender.com/opc_ua_tree/')
            .then((res) => res.json())
            .then((data) => {
                setDataObj(data[0]['tree_structure'][0].Nodes[0]);
                console.log(data[0]['tree_structure'][0].Nodes[0].DisplayName);
                <TreeView
                    aria-label="file system navigator"
                    sx={{ flexGrow: 1, overflowY: 'auto' }}
                    style={{ height: '34vh', width: '100%' }}
                >
                    <TreeItem nodeId={data[0]['tree_structure'][0].Nodes[0].DisplayName} label={data[0]['tree_structure'][0].Nodes[0].DisplayName}>
                        for (let i = 0; i < data[0]['tree_structure'][0].Nodes[0].Nodes.length; i++) {
                            console.log(data[0]['tree_structure'][0].Nodes[0].Nodes[i].DisplayName);
                            <TreeItem nodeId={data[0]['tree_structure'][0].Nodes[0].Nodes[i].DisplayName} label={data[0]['tree_structure'][0].Nodes[0].Nodes[i].DisplayName}>
                                for (let j = 0; j < data[0]['tree_structure'][0].Nodes[0].Nodes[i].Nodes.length; j++) {
                                    console.log(data[0]['tree_structure'][0].Nodes[0].Nodes[i].Nodes[j].DisplayName);
                                    <TreeItem nodeId={data[0]['tree_structure'][0].Nodes[0].Nodes[i].Nodes[j].DisplayName} label={data[0]['tree_structure'][0].Nodes[0].Nodes[i].Nodes[j].DisplayName} />
                                }
                            </TreeItem>
                        }
                    </TreeItem>
                </TreeView>
            });
    }, []);
🤔
 
Last edited:
  • #41
Or isn't it possible to use a for-loop inside the TreeView? Do we maybe have to use an extra function for that? 🤔
 
  • #42
mathmari said:
For the beginning I tried to do that with a non elegant way, to get all data by for loops, I used 3 for loops.
That won't work. You need to build it recursively, something like this:
JavaScript:
  const tree = {
    server: null,
    treeId: null,
    rootNodeId: null,
    nodes: {},
  };

  const loadTree = async () => {
    const data = await fetchTree();
    tree.server = data[0].server;
    tree.treeId = data[0].tree_id;
    tree.nodes = {};
    const { id } = parseNode(data[0].tree_structure[0].Nodes[0], tree.nodes);
    tree.rootNodeId = id;
  };

  const parseNode = (rawNode, nodes) => {
    // Recursively parse the child nodes, adding to this nodes children.
    const children = [];
    (rawNode.Nodes ?? []).forEach((item) => {
      const { id } = parseNode(item, nodes);
      children.push(id);
    });

    // Create this node.
    const node = {
      id: rawNode.Attributes[0].NodeId,
      title: rawNode.DisplayName,
      children,
      attributes: rawNode.Attributes,
    };

    // Save this node to the dictionary.
    nodes[id] = node;

    // Return the node so the caller can get the id.
    return node;
  };
 
  • Like
Likes mathmari
  • #43
pbuk said:
That won't work. You need to build it recursively, something like this:
JavaScript:
  const tree = {
    server: null,
    treeId: null,
    rootNodeId: null,
    nodes: {},
  };

  const loadTree = async () => {
    const data = await fetchTree();
    tree.server = data[0].server;
    tree.treeId = data[0].tree_id;
    tree.nodes = {};
    const { id } = parseNode(data[0].tree_structure[0].Nodes[0], tree.nodes);
    tree.rootNodeId = id;
  };

  const parseNode = (rawNode, nodes) => {
    // Recursively parse the child nodes, adding to this nodes children.
    const children = [];
    (rawNode.Nodes ?? []).forEach((item) => {
      const { id } = parseNode(item, nodes);
      children.push(id);
    });

    // Create this node.
    const node = {
      id: rawNode.Attributes[0].NodeId,
      title: rawNode.DisplayName,
      children,
      attributes: rawNode.Attributes,
    };

    // Save this node to the dictionary.
    nodes[id] = node;

    // Return the node so the caller can get the id.
    return node;
  };

When we initialize the tree, the keys are the one of the first level of the endpoint ? I mean the following :

1667205785313.png
Could you explain to me the function loadTree ? According to the picture I loaded above we have :

tree.server = data[0].server = 41
tree.treeId = data[0].tree_id = 19

Or not? Could you explain to me the following part?

tree.nodes = {};
const { id } = parseNode(data[0].tree_structure[0].Nodes[0], tree.nodes);
tree.rootNodeId = id;With the function parseNode do we parse through all children nodes?

🤔
 
  • #44
Is the idea to buid the tree that we get from the API again from scratch? 🤔
 
  • #45
mathmari said:
Is the idea to buid the tree that we get from the API again from scratch? 🤔
Yes. Working with a nested tree is practically impossible so this is standard practice.

Rather than explain every element I have created a basic but fully working application in plain JavaScript with no dependencies. You can see the code as a GitHub gist and you can see it working below. Note that sometimes the API does not respond first time, I guess this is due to some limitations on the, possibly free, cloud service.

The code doesn't have many comments in, that is deliberate so you can work through it and see how it all works, and then convert it to React.js using your component libraries of choice, and if you wish Redux (although if all you are going to do is display the data you fetch there is no need to use Redux for this).

 
Last edited:
  • #46
mathmari said:
Is the idea to buid the tree that we get from the API again from scratch? 🤔
Of course if whoever had designed the API had done a better job we wouldn't have to do this.

There are some other odd things about the API response, for instance why is Attributes an array with a single element? Why do the id's not have a regular form: many start with "i=" but some look like e.g. "ns=1;s=79f4049c-8266-4758-9c5a-0013e39273d7/0:SessionDiagnostics/0:ActualSessionTimeout"? Why do some nodes exist at more than one point in the tree (hopefully with the same values) e.g. i=2341?

These are rhetorical questions, I think I'm done here.
 

Similar threads

  • · Replies 10 ·
Replies
10
Views
3K
Replies
24
Views
2K
  • · Replies 23 ·
Replies
23
Views
2K
  • · Replies 16 ·
Replies
16
Views
4K
  • · Replies 4 ·
Replies
4
Views
4K
  • · Replies 25 ·
Replies
25
Views
1K
  • · Replies 4 ·
Replies
4
Views
6K
  • · Replies 12 ·
Replies
12
Views
2K
  • · Replies 6 ·
Replies
6
Views
4K
  • · Replies 1 ·
Replies
1
Views
2K