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 get the JSON value as string from content parameter of .onChange()? #173

Closed
jtuchel opened this issue Oct 24, 2022 · 8 comments
Closed
Labels
enhancement New feature or request

Comments

@jtuchel
Copy link

jtuchel commented Oct 24, 2022

I'm using this component inside my Vue project but I think it shouldn't matter.

I created a small reproduction example https://stackblitz.com/edit/vitejs-vite-tfqj8h?file=src/JsonEditor.vue

  • Open the browser console
  • Modify the text in the editor
  • You should see that the JSON content is undefined, although there should be the updated content as plain text

As you can see I have a small component wrapping the editor. This component takes in the raw JSON content as a string via props. Whenever the change event triggers I want to to send back the new string value to the parent via events. Based on type Content = JSONContent | TextContent I check if I can read the plain text from TextContent. If that's not the case I have to deal with content.json. Unfortunately It's not clear to me how to deal with it. As you can see in my example I'm trying to read a raw string from it but it's always undefined.

What needs to be done if the content is of type JSONContent to read the JSON string from it?


Sidenotes

It would be helpful adding a type guard ( as you can see in the example I implemented my own one for now ... )

const isTextContent = function (content: Content): content is TextContent {
  return content.hasOwnProperty("text");
};

Second, if the solution should be straight forward, would you mind adding a function that returns the content as text from the JSON value? Maybe other people might want to read the value from it too.

@josdejong
Copy link
Owner

The editor can indeed give either { text } contents or { json } contents back, depending on the mode, the change being made, and document state (valid, invalid, empty).

Here is a util function to convert JSONContent into TextContent if needed:

function toTextContent(content: Content) : TextContent {
  return isTextContent(content)
    ? content
    : { text: JSON.stringify(content.json) }
}

Good point to add this util function to the library, I'll do that 👍

The isTextContent util function is actually already part of the library, though it is missing in the docs. I'll fix that too.

@josdejong josdejong added the enhancement New feature or request label Oct 24, 2022
josdejong added a commit that referenced this issue Oct 25, 2022
…ontent`, `toTextContent`,

`toJSONContent` (#173)

BREAKING CHANGE:

Not exporting a set of undocumented utility functions anymore: `isValueSelection`,
`isKeySelection`, `isInsideSelection`, `isAfterSelection`, `isMultiSelection`,
`isEditingSelection`, `createValueSelection`, `createKeySelection`, `createInsideSelection`,
`createAfterSelection`, `createMultiSelection`. And not exporting components `SortModal` and
`TransformModal` anymore.
@josdejong
Copy link
Owner

I've now published the following utility functions in v0.9.0 and listed them in the docs: isContent, isTextContent, isJSONContent, toTextContent, toJSONContent.

I've also done some bookkeeping in v0.9.0, removing some non-relevant, undocumented util functions that where exported before.

@nitzcard
Copy link

nitzcard commented Apr 18, 2023

@josdejong I got a similar issue, I wanna get one source of true of valid json / content when "onChange".
And when changing between modes / repairing json it isn't the case.
What do u suggest?

@josdejong
Copy link
Owner

The "one source of truth" that is always holding the editor contents is content, an object that is either {text: string} or {json: JSONValue}.

If you want a simpler model, you can always convert JSON to text, then the contents is just a string. It can be heavy on performance though to convert the JSON to text on every change.

@nitzcard
Copy link

You're right, but I noticed there is a problems with the current way in my setup:
I do the onChange and then if it's text convert it to JSON and propogate.
The conversion itself causes me to lose data on text mode because :

  1. line breaks gets deleted.
  2. When fixing the json in "text" it moves to "json'.

So I prefer to have maybe another valid value which will be used only for onChange and have one type only (object/json).

@josdejong
Copy link
Owner

You can't always represent the text as a valid JSON object, like this content where the user is halfway typing an array. An you will indeed loose indentation: { text: '[1,2,3' }

So I prefer to have maybe another valid value which will be used only for onChange and have one type only (object/json).

You can't (always) have a valid JSON object. You can always represent the contents as a string like I explain. You can also just accept the content model which is also always valid (sometimes holding text, sometimes a JSON object). I did introduce that model for a reason 😅 .

@nitzcard
Copy link

so I suggest this:
Maybe create another event, onChangeValid():
if text is a valid json, it automatically will update the "json", so I know json is always the newest valid value.

@josdejong
Copy link
Owner

If you need that, you can indeed create a onChangeValid (or onChangeJSON) function and trigger it from onChange yourself under the right conditions (to check whether the contents is valid you can check the contentErrors parameter of onChange to see if there was a parse error).

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

No branches or pull requests

3 participants