React-admin: v 3.0.0 Unexpected token u in JSON (json parse undefined) when ../create/?someparams

Created on 24 Nov 2019  路  11Comments  路  Source: marmelab/react-admin

Steps to reproduce:
#/resource/create?anyParams
Unexpected token u in JSON at position 0
seems json is trying to parse undefined variable

Environment

  • React-admin version: 3.0.0
bug v3

All 11 comments

ok here is the problem
/ra-core/esm/controller/useCreateController.js line 106
return state && state.record ? state.record : search ? JSON.parse(parse(search).source) : record;
what is source and why is it needed. (i'cant find it on the docs)
but if i supply any value it works

/resource/create?source=1&&anyParams

Why are you passing GET parameters to the create route?

I have the same issue.

The reason why I'm passing the GET parameters is to filter or pre-fill some fields like in this tutorial: https://marmelab.com/blog/2018/07/09/react-admin-tutorials-form-for-related-records.html

Just ran into this and found the culprit. It's a bug caused by the new CloneButton. The issue is this line expects if there is any query string that it must have source which is a JSON object that's been URL encoded.

You can fix this for now by passing an encoded empty object as source, like so http://localhost:3000/#/posts/create?any_param_works=123&source=%7B%7D.

It's possible to piggyback off this feature to get the functionality you want @akbkk, by encoding your pre-filled form field as a stringified JSON object passed via source=.

Why are you passing GET parameters to the create route?
Its even in the examples (i think it was meant for v 2)
it uses it to set an id for related resource

const AddNewCommentButton = ({ record }) => (
  <Button
    component={Link}
    to={{
      pathname: "/comments/create",
      search: `?post_id=${record.id}`,
    }}
    label="Add a comment"
  >
    <ChatBubbleIcon />
  </Button>
);

Well, trying to use the 'source' parameter resulted in some strange bugs, so I had to do this for every Create screen. It's pretty inconvenient though.

const {classes, location, ...props} = this.props
const { var1, var2, redirect } = parse(location.search)
const createLocation = {...location}
createLocation.search = ''
const initial = { var1, var2 }
return (
  <Create classes={classes} {...props} location={createLocation}>
      <SimpleForm redirect={redirect} initialValues={initial}>

Also having this same issue, also using url params to pre-fill some fields.

My CloneButton allows for a callback that is used to 'tweak' the record being cloned. That way you can have a mechanism to clear or alter in some way fields from the source record. This might alleviate the need to pass params -- which is likely interfering with the clone functionality.

I think it would be cool to have an optional 'tweakSourceRecordCallback' parameter :)

In 3.0, the way to pre-fill some fields in the create form is to pass a stringified object as the source URL parameter. That's what the CloneButton does:

export const CloneButton = ({
    basePath = '',
    label = 'ra.action.clone',
    record = {},
    icon = <Queue />,
    ...rest
}) => (
    <Button
        component={Link}
        to={{
            pathname: `${basePath}/create`,
            search: stringify({ source: JSON.stringify(omitId(record)) }),
        }}
        label={label}
        onClick={stopPropagation}
        {...sanitizeRestProps(rest)}
    >
        {icon}
    </Button>
);

In v2, this feature didn't use the fields of the source get parameter, but all the get parameters. This lead to hard to fix bugs like #3966.

The advanced tutorials were indeed written for v2. For v3, the right syntax should be:

const AddNewCommentButton = ({ record }) => (
  <Button
    component={Link}
    to={{
      pathname: "/comments/create",
-     search: `?post_id=${record.id}`,
+     search: `?source=${JSON.stringify({ post_id: record.id })}`,
    }}
    label="Add a comment"
  >
    <ChatBubbleIcon />
  </Button>
);

Sorry for not mentioning it in the UPGRADE guide - we figured that, since both the Create page and the CloneButton were changed at the same time, it was a backwards compatible change. We forgot that we had documented the inner workings of CloneButton in an advanced tutorial, which made it a public API.

So this is a breaking change, not a bug. I'll document it in the Upgrade guide.

Also, there is indeed a small bug: useCreateController should not try to parse the search.source field if it's not present. I'll also fix it in a future PR.

I also just discovered another, seemingly more intended, way to do this:

https://github.com/marmelab/react-admin/blob/master/docs/CreateEdit.md#prefilling-a-create-record

Using state it's possible to pass pre-filled data to create without using query params at all.

const AddNewCommentButton = ({ record }) => (
  <Button
    component={Link}
    to={{
      pathname: "/comments/create",
      state: { post_id: record.id },
    }}
    label="Add a comment"
  >
    <ChatBubbleIcon />
  </Button>
);

Great stuff!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ericwb picture ericwb  路  3Comments

samanmohamadi picture samanmohamadi  路  3Comments

9747749366 picture 9747749366  路  3Comments

phacks picture phacks  路  3Comments

Dragomir-Ivanov picture Dragomir-Ivanov  路  3Comments