CarlosNZ/json-edit-react

Support for `Date` objects

antonio-ivanovski opened this issue ยท 10 comments

Suggestion
The JS Date object should be supported as Date value in the editor.

I am aware that Date is not valid JSON value.
Use case

  • The JsonEditor can be used to display Date data
  • I am using the JsonEditor to display developer data that will make request with and to view the response data. For easier working with the data, the API layer does the conversion of number/string->Date.

You should be able to do this with a Custom Node, I think.

There's actually an example of a DatePicker custom component in the repo, which you can see here: https://github.com/CarlosNZ/json-edit-react/blob/main/demo/src/customComponents/DateTimePicker.tsx

However, that expect dates as ISO strings, which is still valid JSON, whereas I think you're wanting actual Date objects in the data, right? But it should still be possible with a custom component, you'll just have to change the condition function to recognise dates, and then decide how you want them displayed and edited.

I'm happy to help you work through what you need to find a solution, as I'd like this package to be flexible enough to easily handle things like this. So let me know how you're getting and what might be getting in your way.

(Also, if you do come up with a good custom component, please share it, as I'd like to start showcasing a library of custom components for people to use)

Thanks for the response @CarlosNZ

I have looked into using Custom Node but I am dissatisfied with the result I am getting. I just used the StringDisplay component from the library, but the issue is that the Date as an object is being wrapped into the Object wrapper.

Here it is how it looks for the expiresAt:

Image

What I want to achieve is similar look and feel to the existing style and get the Date rendered aout in some field value. Looked into the library and maybe exposing ValueNodeWrapper would be helpful to achieve this.

Maybe the best path forward is to have library exposed custom component for Date values, similar to the exposed Link String custom node.

Ah, the problem is that because the "Date" is an Object, the component is treating it as a "Collection" node rather than a "Value", hence it's nested inside the braces.

Bit annoying, yeah. Leave it with me and I'll try and come up with a solution (or at least a workaround)

Thanks @CarlosNZ, that was exactly the point and conclusion I had looking at the code.

Maybe the best path forward is to expose some of the building blocks, especially the wrappers. Then implementing the Date custom node would be easy.

I can fix this pretty easily by adding an additional check to my isCollection function to ignore Date objects. After that it's going to work pretty well, I think.

I can fix this pretty easily by adding an additional check to my isCollection function to ignore Date objects. After that it's going to work pretty well, I think.

Possible solution. Not sure if the library should handle Date objects by default. Maybe sane option is to display the Date objects as string values with value of Date.toISOString()?

I can fix this pretty easily by adding an additional check to my isCollection function to ignore Date objects. After that it's going to work pretty well, I think.

Possible solution. Not sure if the library should handle Date objects by default. Maybe sane option is to display the Date objects as string values with value of Date.toISOString()?

Yeah, I'm not going to "handle" dates so much as just not treat them as a collection (as it's a whole different React component, with a whole lot of different rendering logic). We can do the toIsoString() thing, perhaps, but I still need to modify isCollection otherwise the Date will get captured by the Collection component and never even get the chance to be rendered as a string.

Hi @antonio-ivanovski, this should be working correctly now in v1.25.5.

You can define a very basic Date custom component with this definintion (which goes in the customNodeDefinitions array:

{
  condition: (nodeData) => nodeData.value instanceof Date,
  element: (props) => {
    const { nodeData, isEditing, setValue, getStyles, canEdit, value, handleEdit } = props
    return isEditing ? (
      <StringEdit
        styles={getStyles('input', nodeData)}
        pathString={toPathString(nodeData.path)}
        {...props}
        value={value instanceof Date ? value.toISOString() : (value as string)}
        setValue={setValue as React.Dispatch<React.SetStateAction<string>>}
        handleEdit={() => {
          const newDate = new Date(value as string)
          handleEdit(newDate as any)
        }}
      />
    ) : (
      <StringDisplay
        {...props}
        styles={getStyles('string', nodeData)}
        canEdit={canEdit}
        pathString={toPathString(nodeData.path)}
        value={nodeData.value.toLocaleString()}
      />
    )
  },
  showEditTools: true,
  showOnEdit: true,
}

There's no error handling, or anything fancy, but it displays a locale string in normal view, an ISO string when editing, and converts it to a Date object on submission.

I've started a collection of custom components now (bit rough around the edges, but it's a start), and the Date Object one is working quite well I think. You can copy the code as you see fit @antonio-ivanovski .

Library root/ReadMe

DateObject component

Looking good. Thanks for the great support!

Image