craft.js icon indicating copy to clipboard operation
craft.js copied to clipboard

How to delete a linked node?

Open wf08314110101 opened this issue 2 years ago • 9 comments

Describe the bug craft json: { "ROOT": { "type": { "resolvedName": "PageContainer" }, "isCanvas": true, "props": { }, "displayName": "APP", "hidden": false, "nodes": [ "dseJuw_N09" ], "linkedNodes": {} }, "dseJuw_N09": { "type": { "resolvedName": "TabsWrapper" }, "isCanvas": false, "props": { }, "displayName": "Tabs", "custom": {}, "parent": "ROOT", "hidden": false, "nodes": [], "linkedNodes": { "simple-tabpanel-0": "4UMnl2CvbA", "simple-tabpanel-1": "7nsOGA7ixG", "simple-tabpanel-2": "OQA1r8DNvq" } }, "4UMnl2CvbA": { "type": { "resolvedName": "Container" }, "isCanvas": true, "props": { }, "displayName": "Container", "custom": {}, "parent": "dseJuw_N09", "hidden": false, "nodes": [], "linkedNodes": {} }, "7nsOGA7ixG": { "type": { "resolvedName": "Container" }, "isCanvas": true, "props": { }, "displayName": "Container", "custom": {}, "parent": "dseJuw_N09", "hidden": true, "nodes": [], "linkedNodes": {} }, "OQA1r8DNvq": { "type": { "resolvedName": "Container" }, "isCanvas": true, "props": { }, "displayName": "Container", "custom": {}, "parent": "dseJuw_N09", "hidden": true, "nodes": [], "linkedNodes": {} } }

To Reproduce Steps to reproduce the behavior:

const { actions } = useEditor() actions.delete("OQA1r8DNvq")

Error: Invariant failed: Attempting to delete a top-level Node

Expected behavior

Screenshots If applicable, add screenshots to help explain your problem.

Additional context Add any other context about the problem here.

Your environment

Software Version(s)
craft.js
React
TypeScript
Browser
npm/Yarn
Operating System

wf08314110101 avatar Dec 14 '23 09:12 wf08314110101

Same issue.

jorgegonzalez avatar Feb 08 '24 21:02 jorgegonzalez

@prevwong is deleting linked nodes possible?

jorgegonzalez avatar Feb 08 '24 21:02 jorgegonzalez

Yes, same issue here.

raghuwarWeb avatar Feb 29 '24 11:02 raghuwarWeb

I'm having a similar issue. The error thrown is:

react-dom.development.js:20724 Uncaught 
Error: Invariant failed: Attempting to delete a top-level Node
    at invariant (tiny-invariant.js:16:11)
    at eval (index.js:43:38192)
    at Array.forEach (<anonymous>)
    at Object.delete (index.js:43:38100)
    at eval (index.js:57:8173)
    at e.produce (immer.esm.mjs:25:16108)
    at e.produceWithPatches (immer.esm.mjs:25:16689)
    at eval (index.js:57:7864)
    at eval (index.js:57:8966)
    at e.reduce.e.<computed> (index.js:57:9462)
    at onClick (PanelControllerSettingsPanel.tsx:72:19)
    at HTMLUnknownElement.callCallback (react-dom.development.js:20565:14)
    at Object.invokeGuardedCallbackImpl (react-dom.development.js:20614:16)
    at invokeGuardedCallback (react-dom.development.js:20689:29)
    at invokeGuardedCallbackAndCatchFirstError (react-dom.development.js:20703:25)
    at executeDispatch (react-dom.development.js:32128:3)
    at processDispatchQueueItemsInOrder (react-dom.development.js:32160:7)
    at processDispatchQueue (react-dom.development.js:32173:5)
    at dispatchEventsForPlugins (react-dom.development.js:32184:3)
    at eval (react-dom.development.js:32374:12)
    at batchedUpdates$1 (react-dom.development.js:24953:12)
    at batchedUpdates (react-dom.development.js:28844:12)
    at dispatchEventForPluginEventSystem (react-dom.development.js:32373:3)
    at dispatchEvent (react-dom.development.js:30141:5)
    at dispatchDiscreteEvent (react-dom.development.js:30112:5)
    ```

metricmogul avatar Aug 13 '24 20:08 metricmogul

Same issue.

ck6u4dj0 avatar Aug 14 '24 11:08 ck6u4dj0

PSA the only way I got this to work properly was processing the editor state in my backend every time a change is published, deleting the node there, and then have Craft re-render with the updated state

jorgegonzalez avatar Aug 14 '24 12:08 jorgegonzalez

thanks @jorgegonzalez!

fwiw this is my workaround:

  const deleteNode = (nodeId: string) =>{
    if(!query.node(nodeId).isLinkedNode()){
      actions.delete(nodeId);
    }else{
      const ancestors = query.node(nodeId).ancestors();
      if (ancestors.length > 0) {
        deleteNode(ancestors[0]);
      }
    }
  }

ck6u4dj0 avatar Aug 14 '24 16:08 ck6u4dj0

@ck6u4dj0 your function deletes linkedNode's parent, which is not what is generally needed. I have a ColumnsBlock component. If the user decreases the number of columns I need to delete the linked nodes that are the extra columns. I do not want (and cannot) delete the ColumnsBlock itself.

I find it frustrating that when my ColumnsBlock renders, if it does not render the extra column, that component remains in the editor's state anyway, even though it was never rendered.

@prevwong, this is a serious issue. Is there a way to delete linked nodes?

edit: I may have solved this similar to @jorgegonzalez, but in the front end. I call const state = JSON.parse(query.seriealize()), manipulate the state, then re-render with action.deserialize(state). It works, but it's slow and scrolls to the top of the page. It's extra frustrating that async functions cannot be waited on.

eschiebel avatar Aug 20 '24 15:08 eschiebel