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

v 3.0.0 Unexpected token u in JSON (json parse undefined) when ../create/?someparams #4031

Closed
Abenezer opened this issue Nov 24, 2019 · 11 comments · Fixed by #4053
Closed

v 3.0.0 Unexpected token u in JSON (json parse undefined) when ../create/?someparams #4031

Abenezer opened this issue Nov 24, 2019 · 11 comments · Fixed by #4053
Assignees
Labels

Comments

@Abenezer
Copy link

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
@Abenezer
Copy link
Author

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

@fzaninotto
Copy link
Member

Why are you passing GET parameters to the create route?

@akbkk
Copy link

akbkk commented Nov 25, 2019

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

@mutewinter
Copy link

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

@Abenezer
Copy link
Author

Abenezer commented Nov 25, 2019

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

@akbkk
Copy link

akbkk commented Nov 26, 2019

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}>

@b-raines
Copy link
Contributor

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

@qpointsystems
Copy link

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

@fzaninotto
Copy link
Member

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.

@mutewinter
Copy link

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

@qpointsystems
Copy link

Great stuff!

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

Successfully merging a pull request may close this issue.

6 participants