3

i am using react-flow-renderer in my project. and we have a requirement that we want to delete the element by clicking on it.

enter image description here

I had try the following code.

const onElementsRemove = (elementsToRemove) =>
setElements((els) => removeElements(elementsToRemove, els));

I also put this

enter image description here

But we do not want this to.

Could any one have any idea about how to do this it would be a great help

General Grievance
  • 4,555
  • 31
  • 31
  • 45
Dharmendra Soni
  • 145
  • 1
  • 4
  • 9
  • Can you please show us some relevant code? You should consider including the `removeElement` function and also the code that shows how you store or render your elements, do you keep them on a state? – Kevin Haxhi Aug 08 '21 at 08:58

4 Answers4

8

I actually just solved this myself using the React Flow controls with a custom delete button. In the <ReactFlow> component I added the onElementClick prop that uses a React hook to store the selected element in state. In the onClick prop for the button I have another hook that gets the selected element from state, all edges for the tree, and call the getConnectedEdges() which will return all edges connected to the selected element. Then just pass an array with the selected element and connected edges to your onElementsRemove().

Here is the documentation for onElementClick. https://reactflow.dev/docs/api/component-props/

<ReactFlow 
    className={flowStyles}
    elements={elements}
    onElementClick={onClickElement}
>
  <Controls showInteractive={false}>
    <ControlButton onClick={onClickElementDelete}>
      <DeleteIcon />
    </ControlButton>
  </Controls>
</ReactFlow>
const onClickElement = useCallback((event: ReactMouseEvent, element: Node | Edge) => {
  // Set the clicked element in local state
  setState({
    clickedElement: [element]
  })
}, [])

Here is the documentation for getConnectedEdges. https://reactflow.dev/docs/api/helper-functions/

  const onClickElementDelete = useCallback(() => {
    // Get all edges for the flow
    const edges = elements.filter((element: Node | Edge) => isEdge(element))
    // Get edges connected to selected node
    const edgesToRemove = getConnectedEdges(state.clickedElement, edges)

    onElementsRemove([...state.clickedElement, ...edgesToRemove])
    }
  }, [elements, onElementsRemove, state.clickedElement])
1

You have to add delete function in the data property of your custom node, and on click of the delete button of your custom node you have to call that function

While creating custom node =>

const newNode = {
  id: nodeID,
  type,
  position,
  data: {
      onDelete : yourFunctionToDelete
  }}

Custom Node Code in the delete button => onClick={props.data.onDelete}

Harsh
  • 11
  • 1
  • 1
    Have-you tried this? Don't think this can work since the state passed to the newNode is "fixed" in time so if you add two nodes and try to delete the first one, then your second node will disappear as well. – Benobab Jan 21 '22 at 13:27
  • I can confirm. Passing callback in data is problematic for that reason. Official docs mention that using a separate state management solution outside the component, and triggering actions of the store from inside the node can solve this. – Noxware Oct 08 '22 at 20:22
1

You can use a separate state management library, outside your component, and trigger actions from inside the node directly.

This technic is mentioned in the official doc Using a State Management Library .

There it says the following:

As you might have seen in the previous guides and examples, React Flow can easily be used with a local state for handling the nodes and edges of your diagram. When your app grows and you want to alter your state from within your nodes for examples, things can easily get more complex. To avoid passing down functions through the node data field, you could use a React context or add a state management library as explained in this guide.

If for example, you make a Zustand store as shown in the doc, and expose a deleteNode action from it, then, you can access it from your custom node with const deleteNode = useStore((s) => s.deleteNode);.

Noxware
  • 99
  • 3
  • 8
0

I could achieve the following using the function below.

const deleteNodeById = (id) => {
    flowInstance.setNodes((nds) => nds.filter((node) => node.id !== id))
  }

And passing this function to my delete button (In my case mui delete icon)

<DeleteOutlined
 onClick={() => deleteNodeById(data.id)}
/>

ARMEL FOPA
  • 206
  • 3
  • 8