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

Add a 'target' field to <ReferenceField> #5581

Closed
nickgrealy opened this issue Nov 24, 2020 · 5 comments
Closed

Add a 'target' field to <ReferenceField> #5581

nickgrealy opened this issue Nov 24, 2020 · 5 comments

Comments

@nickgrealy
Copy link

nickgrealy commented Nov 24, 2020

Is your feature request related to a problem? Please describe.
I want to use a ReferenceField, to lookup a (single) resource based on a foreign field name (e.g. voucherCode not id). However ReferenceField only allows me to use the default foreign field id.

I imagine this is a pretty common use case, especially in existing databases.

Please correct me if I'm using the wrong component (or wrongly using the right component!).

Describe the solution you'd like
I'd like ReferenceField to behave similarly to ReferenceManyField, in that I can supply a foreign field name to match against (i.e. target={...}).

e.g.

I'd like a ReferenceField to support a target attribute...

<ReferenceField
  source={field}
  reference={collection}
  target={matchForeignField}
>
  ...
</ReferenceField>

... similar to how ReferenceManyField already behaves.

<ReferenceManyField
  source={field}
  reference={collection}
  target={matchForeignField}
>
  ...
</ReferenceManyField>

Describe alternatives you've considered
I've tried using ReferenceManyField - which can lookup the field successfully, but throws an error when I return to list view after updating an object (screenshot attached)

attempt-error

@MicroJackson
Copy link

Might totally misunderstand your question but you can just put voucherCode in your source if you received it from your backend.

                    <ReferenceField
                        source="voucherCode"
                        reference="your_resource_in_app"
                    >
                        <TextField source="name" />
                    </ReferenceField>

Creates a request like: /your_resource_in_app/voucherCode/
Then you need to capture that in your backend and deal with it accordingly.

As far as the error goes: #5054 should have fixed it I think. Maybe update your React Admin?

@nickgrealy
Copy link
Author

nickgrealy commented Nov 24, 2020

Thanks @MicroJackson.

You're right, one workaround could be to modify the backend. If I was going to do that, I'd simply create a custom mapping (id => voucherCode) when retrieving the data.

Another workaround (to keep the "link" behaviour), would be to use <Link ... /> to filter the target data to just the requested resource. Downside is, I can't "lookup" target fields to display, AND the Field doesn't know whether the target resource exists or not (so it's always displayed).

e.g.

image

I'd prefer to continue to investigate adding a target attribute - because it seems intuitive and logical. (I was looking for it in the documentation, before realising it didn't exist).

re: #5054 - I'm not sure that ReferenceManyField is the correct component I should be using, as I'm currently only looking for a 1-to-1 mapping.

I'm already on the latest - "react-admin": "3.10.2".

@nickgrealy
Copy link
Author

nickgrealy commented Nov 26, 2020

Looking for some guidance on how to proceed (@fzaninotto)) - happy to get my hands dirty if there's interest in including this feature.

My initial investigation...

ReferenceField - currently calls useGetMany with an array of (one) id. I imagine we could do something similar, but call useGetManyReference instead.

Two options:

  1. (my preference) we could extend ReferenceField to modify it's underlying call (useGetMany vs useGetManyReference) based on the presence of a target attribute.
  2. Or we could create a separate component specifically for handling "get by reference" (although I don't know what you'd call it - ReferenceField sums it up nicely).

Call Chain

ReferenceField calls -> useReference({ reference, id })

<PureReferenceFieldView
{...props}
{...useReference({
reference: props.reference,
id: get(record, source),
})}
resourceLinkPath={resourceLinkPath}
>
{children}
</PureReferenceFieldView>

which calls -> useGetMany(reference, [id])

export const useReference = ({ reference, id }: Option): UseReferenceProps => {
const { data, error, loading, loaded } = useGetMany(reference, [id]);
return {
referenceRecord: error ? undefined : data[0],
error,
loading,
loaded,
};
};

proposed? -> useGetManyReference(resource, target, id, pagination, sort, fiter, referencingResource, options)

const useGetManyReference = (
resource: string,
target: string,
id: Identifier,
pagination: Pagination,
sort: Sort,
filter: object,
referencingResource: string,
options?: any
) => {

@djhi
Copy link
Collaborator

djhi commented Nov 26, 2020

Duplicate of #2022. Please see @fzaninotto answer

@djhi djhi closed this as completed Nov 26, 2020
@nickgrealy
Copy link
Author

nickgrealy commented Nov 26, 2020

Hi @djhi - thanks for the response. Just one question if you'll humour me.

First - agree it's a duplicate.

React-admin requires that the records it manipulates have an id attribute. If your backend doesn't provide one, it's the job of the dataProvider to do the translation.

👍 - No problem. All my records have my records have an id field.

Adding the target prop that you ask would imply leaking this "adapter" logic outside of the dataProvider. We won't do it.

Then why does ReferenceManyField have a target field?

UPDATE I'll ask Francois over here (if he doesn't mind me posting on old issues): -> #2022 (comment)

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

No branches or pull requests

3 participants