Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to delete a linked node? #592

Open
wf08314110101 opened this issue Dec 14, 2023 · 9 comments
Open

How to delete a linked node? #592

wf08314110101 opened this issue Dec 14, 2023 · 9 comments

Comments

@wf08314110101
Copy link

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 wf08314110101 changed the title How tp delete a linked node? How to delete a linked node? Dec 14, 2023
@jorgegonzalez
Copy link

Same issue.

@jorgegonzalez
Copy link

@prevwong is deleting linked nodes possible?

@raghuwarWeb
Copy link

Yes, same issue here.

@metricmogul
Copy link

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)
    ```

@ck6u4dj0
Copy link

Same issue.

@jorgegonzalez
Copy link

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

@ck6u4dj0
Copy link

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]);
      }
    }
  }

@eschiebel
Copy link

eschiebel commented Aug 20, 2024

@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.

@iDenisM
Copy link

iDenisM commented Oct 25, 2024

I'm also struggling with linkedNodes in sense that you can not have easily access to them link add, remove.
My work around this issue, and to be able to manipulate the nodes inside of the linkedNodes is:
I create a Fragment component for my CraftJs.
I'm adding to the linkedNodes a key fragment (could be any key) and a random id with the value. Them I'm creating the basic data for the Fragment SerializedNode schema.
something like this:

{
  "ROOT": {
    "type": { "resolvedName": "Container" },
    "isCanvas": true,
    "props": {
      "text": "lorem"
    },
    "displayName": "Container",
    "custom": {},
    "hidden": false,
    "nodes": [],
    "linkedNodes": { "fragment": "Fr6t8DozR1" },
    "parent": null
  },
  "Fr6t8DozR1": {
    "type": { "resolvedName": "Fragment" },
    "isCanvas": true,
    "props": {},
    "displayName": "Fragment",
    "custom": { "displayName": "Fragment" },
    "hidden": false,
    "nodes": [],
    "linkedNodes": {},
    "parent": "ROOT"
  }
}

In my case I want to fetch some data and display it front end as a list of cards. But this card is not something I want to change it's just a graphical representation of the final result. So once I have the response I'm creating SerializedNodes in such a way that all these nodes have as parent the Fragment component

{
  "N1xWvEElbl": {
    "type": { "resolvedName": "Card" },
    "isCanvas": true,
    "props": {...},
    "displayName": "Card",
    "custom": { "displayName": "Card" },
    "hidden": false,
    "nodes": [],
    "linkedNodes": {},
    "parent": "Fr6t8DozR1"
  },
  "NyQzD4EgWe": {
    "type": { "resolvedName": "Card" },
    "isCanvas": true,
    "props": {...},
    "displayName": "Card",
    "custom": { "displayName": "Card" },
    "hidden": false,
    "nodes": [],
    "linkedNodes": {},
    "parent": "Fr6t8DozR1"
  },
  "VyFGPVNlZl": {
    "type": { "resolvedName": "Card" },
    "isCanvas": true,
    "props": {...},
    "displayName": "Card",
    "custom": { "displayName": "Card" },
    "hidden": false,
    "nodes": [],
    "linkedNodes": {},
    "parent": "Fr6t8DozR1"
  }
  ...
}

Using the query.parseSerializedNode function I'm transforming all of these SerializedNodes to Nodes and then with query.add I'm adding them as children to the Fragment component.
The good thing about this approach is that now I need to manipulate just the children of the Fragment and not the node itself.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants