Steps to reproduce:
#/resource/create?anyParams
Unexpected token u in JSON at position 0
seems json is trying to parse undefined variable
Environment
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
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!