Reselecting a Node

Hello there! I need to re-select a Node that was selected prior to manually re-rendering ReactDiagram. I looked into many prior topic questions and the documentation but it is not selecting the Node.

On my selectionChanged event function callback handler we set the entire selected Node in a Redux state. After manually re-rendering ReactDiagram I’m calling diagram.select(Node) which is also still .selected = true

See attached screenshot.

any thoughts…? thank you!


useDiagramEventHandlers.ts - oast-mr - Visual Studio Code 2023-04-17 at 9.05.04 AM

Why are you manually re-rendering the diagram? Normally doing so would lose transient state such as the current Diagram.selection as well as the current Diagram.position and Diagram.scale.

How did I know you’d ask that… we’re performing quite a few data source changes based on user interaction, outside of ReactDiagram and ReactPalette awareness and we need to re-render GoJs.

OK. The Diagram.selection collection is the set of Nodes and Links that are Part.isSelected. If you can remember the collection of selected Node.key values, and possibly the Link.key values if you care about them, then you can re-select them after the Nodes and Links have been discarded and then re-created by finding the new Node (or Link) for each key value.

That means calling Diagram.findNodeForKey and then setting Part.isSelected to true if you do find that Node.

The good news is that we only allow 1 Node to be selected at once, at all times so, that makes things a little (or a lot) easier.

I think I’m calling the correct key value to find my Node but it’s not finding it. I’m attaching a short video clip to be safe…

I think the reason that I’m not finding my Node is due to the way React architecture works and the use of hooks, render cycles etc. The way ReactDiagram loads/renders.

When I call the method diagram.findNodeForKey(‘8’) I believe that my Model hasn’t loaded yet. This method is being called from within my hook useGoJsInitDiagram() that returns the Diagram instance into the ReactDiagram component.

<ReactDiagram
nodeDataArray={diagramData.nodeDataArray}
initDiagram={useGoJsInitDiagram(diagramEventHandlers, selectedDocletTypeNode)}
/>

I’m wondering, maybe I should load the nodeDataArray into the Diagram instance within the hook, instead of using the prop < ReactDiagram nodeDataArray={} />

So, if I call the method diagram.findNodeForKey(‘8’) AFTER nodeDataArray has loaded into Diagram instance, my Node “should” be found… ???

Thank you!!

After one sets Diagram.model with a new Model, or after a call to Model.mergeNodeDataArray as done by a gojs-react component when seeing new data, the corresponding Node(s) should exist but probably have not been fully initialized yet. So if you can find it, you can set its Part.isSelected property.

Hi there, thank you. I’m just simply unable to make this work. I’m reading all the Docs, API Docs etc and I cannot programmatically select a Node on initial load; I guess I just don’t quite understand your instructions either… I’m inclined to use my own “selected” prop in my data model and track it through my own Redux State, which kinda sucks, but I can’t figure this out in React, which makes things really hard due to the Render Cycles.

I can’t find the Node through the method diagram.findNodeForKey(‘8’) and I do not know at what point in the React code this method should have access to the Model data.

You can probably add an ‘InitialLayoutCompleted’ diagram listener and select the node there.

It might look something like this:

  const diagramRef = useRef(null);  // be sure this is set on ReactDiagram

  // add/remove listeners on mount/unmonunt
  useEffect(() => {
    if (diagramRef.current === null) return;
    const diagram = diagramRef.current.getDiagram();
    const onLayoutCompleted = (e) => {
      e.diagram.select(e.diagram.nodes.first());  // update this line to select your desired node
    };
    if (diagram instanceof go.Diagram) {
      diagram.addDiagramListener('InitialLayoutCompleted', onLayoutCompleted);
    }
    return () => {
      if (diagram instanceof go.Diagram) {
        diagram.removeDiagramListener('InitialLayoutCompleted', onLayoutCompleted);
      }
    }
  }, []);

I took your code example but I do not have access to the go object therefore I can’t check if (diagram instanceof go.Diagram)

I removed the if checks but the event does not fire even though the breakpoints hit, meaning the listeners code lines are firing. I moved this logic into the hook initDiagram={useGoJsInitDiagram()} and it does execute, so, the useEffect logic does not work though

My custom hook initDiagram={useGoJsInitDiagram()} is the one importing the go object…

The init… functions are just that, functions that are only called when the ReactDiagram/Palette is first initialized when mounted.

You should be defining any event handlers elsewhere; in my code above, that’s a simple useEffect. Here’s the full example: gojs-react-hooks-initSelect - CodeSandbox

Note how the initDiagram function does not rely on any state or props whatsoever.

Ok ok. I see.

I’m going to pass the go object into my init hook as an argument and that will allow me to move all my state-dependent event handlers up to my React component and that should fix my Stale state issue; because the issue with your codeSandbox example is that it is a code architecture (structure) that grows HUGEEE and so I have to use custom hooks to move as much logic as possible outside the React component BUT, my flaw was to NOT pass the go object instance into the init hook therefore being forced to import * as go from ‘gojs’; from within the hook itself, causing my dreadful drama :-)

I’ll refactor and report back if I have any further issues but I think it should work… thank you.

Ok.

As I mentioned in the other thread, you could always design your own component to render a Diagram if you want to do things another way. All the gojs-react code is available, so you could make your own choices while understanding the way things are done with our solution. Note that gojs-react uses class component syntax and hasn’t been rewritten with hooks syntax.

1 Like