#Dynamic node generation.

1 messages · Page 1 of 1 (latest)

still remnant
#

Is there any way of generating nodes dynamically by code? Basically add nodes to my flow and set their values up.
Would also be nice I could also generate the contents of the node itself dynamically (the handles it has, add divs and text to it, inputs and etc.)

#

Something that would be nice is if I could call a function to create a blank node, and then call functions to draw elements inside it.

#

I will also need to figure out how to link those nodes after all nodes in the flow have been drawn

rugged granite
still remnant
#

@vital knot

vital knot
#

?

still remnant
#

Now I need to figure out how to link nodes programatically...

#

And maybe if we can dynamically add things inside them (handles, paragraphs, divs, input elements) dynamically.

#

@vital knot All you need to do basically is an array append into the nodes array lol

winged siren
#

Linking nodes is just adding an edge

const [edges, setEdges] = useState(initialEdges)

function connectNodes(sourceId: string, targetId: strng) {
  setEdges(edges => [...edges, { id: `e${sourceId}-${targetId}`, source: sourceId, target: targetId }]
}
#

Or just do it like the examples do it with the onConnect handlers

const onConnect = useCallback((params) => setEdges((eds) => addEdge(params, edges)), []);
const connectNodes(sourceId: string, targetId: string) {
  setEdges((eds) => addEdge({ source: sourceId, target: targetId }, edges))
}

Same thing basically

still remnant
#

it does absolutely nothing

#

had to remove the "initialnodes" thing since it wasn't working properly

rugged granite
#

please provide a full example as a codesandbox or repo. Otherwise it's hard to tell what is going on.

still remnant
#

The file is too big to be sent here as .zip.

#

I don't think I can upload this to codesandbox either

#

you may have to join the repository.

rugged granite
#

App.tsx is already better than a part of it

still remnant
rugged granite
#

when you do nodes={INITIAL_NODES}

#

it won't use the nodes array that you update with setNodes

#

it should be

#

nodes={nodes}

#

onNodesChange={onNodesChange}

still remnant
#

is this all?

rugged granite
#

not sure

still remnant
#

seems to be working now...

#

can I assign a type to a generated node?

rugged granite
#

sure

still remnant
#

I mean, how far can I go with this? seems quite neat.

rugged granite
#

well ..

#

😄

#

idk

still remnant
#

can I call onAddNode as a function?

rugged granite
#

where

still remnant
# rugged granite where

Well, if I can use it in any possible context it would be nice.
My goal is to create a function that is called as soon as the page loads that already inserts a few nodes into the canvas according to some JSON data.

For now, for the sake of prototyping I will make a small function called as soon as the page loads that will insert 10 nodes into the canvas.

#

I won't lie I'm really struggling to understand most of this library, I'm only being able to carry on with the project I'm currently doing thanks to my development assistant @/JorgeB, who is the one who recommended me this library since I'm coding an application for viewing Blender node materials on the web so we have been looking for some way of drawing node graphs in a browser.

#

Is that possible?

#

Basically creating an onAddNode() function?

rugged granite
#

sure you can add an onAddNode function

still remnant
rugged granite
#

onAddNode would be an event handler when I get it right

still remnant
#

not being able to set it up properly.

rugged granite
#

where / how do you want to call it?

#

when someone presses a button?

still remnant
#

I didn't create this function yet however.

rugged granite
#

I would call it when you get the data

#

transform the data to nodes and edges

#

and use that as initial values

still remnant
# rugged granite I would call it when you get the data

The moment I get the data is exactly as soon as the page loads...

The JSON will be pulled out of the database depending of the current link being viewed, and then a loop will create nodes depending on the amount of keys that exist on the file and set them up according to the values inside the JSON

rugged granite
#

sounds good

#

load data -> transform data to nodes and edges -> pass it to useNodesState/ store / whatever -> pass it as props to ReactFlow component

still remnant
#

My idea is making the JSON be read inside a loop that will create all the nodes.

#

So I would need an onAddNode() function to be called for every JSON key read.

rugged granite
#

this has nothing to do with react flow

#

and I think, that you want to create one result with a set of nodes and edges

frank condor
#
import { z } from "zod";
const Flow: FC<{ initialNodes: Node[] }> = ({ initialNodes }) => {
  const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
  return (
    <ReactFlow
      nodeTypes={nodeTypes}
      nodes={nodes}
      onNodesChange={onNodesChange}
      fitView
    >
      <Background />
      <Buttons />
    </ReactFlow>
  );
};

function App(props: any) {
  const data = {
    id: "child_0.8168920598333149",
    data: {
      label: "ssdas dsa d asd asd",
    },
    position: {
      x: 25.80090497737558,
      y: 113.34690799396681,
    },
    className: "light",
    parentNode: "static-delegate",
    extent: "parent",
    type: "inputItem",
    width: 250,
    height: 63,
    selected: false,
    positionAbsolute: {
      x: -284.1990950226244,
      y: 123.34690799396681,
    },
    dragging: false,
  } as unknown as Node;

  const initialNodes = NodeSchema.safeParse(data).success
    ? [...defaultNodes, data]
    : defaultNodes;

  return (
    <ReactFlowProvider>
      <Flow {...props} initialNodes={initialNodes} />
    </ReactFlowProvider>
  );
}

export const NodeSchema = z.object({
  id: z.string(),
  data: z.object({
    label: z.string(),
  }),
  position: z.object({
    x: z.number(),
    y: z.number(),
  }),
  className: z.string(),
  parentNode: z.string(),
  type: z.string(),
  extent: z.string(),
  width: z.number(),
  height: z.number(),
  selected: z.boolean(),
  positionAbsolute: z.object({
    x: z.number(),
    y: z.number(),
  }),
  dragging: z.boolean(),
});
```       This is the pattern I use.
still remnant
#

Am I allowed to use this?

frank condor
#

It is just a common pattern of React, passing data as props to component. It is not react-flow specific. You validate data before passing it. You can use IsNode() from the lib. https://reactflow.dev/api-reference/utils/is-node

Test whether an object is useable as an Node. In TypeScript this is a type guard that will narrow the type of whatever you pass in to Node if it returns true.

still remnant
frank condor
#

why not? hydrate react-flow with initial props and modify anytime anywhere.

still remnant
#

It's a pretty good library, but it's beyond inunderstandable.

frank condor
#

to be honest, it is not the library. It is you. How to hydrate component is React/frontend problem.