ReferenceInput does not fetch current value
I am writing a AutoComplete input that stores values from users table login field. The code is as follows. Everything works just fine if perPage is large enough to include all records from users table. However, if perPage is small, then I am missing the current value in the drop-down box, and value appears to be empty
<ReferenceInput
source='owner' // reference owner field in the current table; it contains users.login value
reference='users' // use users table as reference
page={1}
perPage={5}
queryOptions={{ refetchOnWindowFocus: false, retry: false }}
>
<AutocompleteInput
optionValue='login' // use users.login instead of users.id
/>
</ReferenceInput>
Root-cause:
Reference input performs 2 queries from useReferenceInputController
useGetListto fetch possible valuesuseReferenceto fetch current values
The issue with useReference query is that it expects value to include id. In my example above, I am using users.login attribute instead of users.id as optionValue; as the result, the only records that are received are the records returned by useGetList and, due to pagination settings, the current value may be missing from available choices and will not be displayed.
Proposed fix
- Add
optionValueattribute toReferenceInputwhich defaults toid - If
optionValue === 'id', continue usinguseReferenceas displayed below - If
optionValue !== 'id', fetch current selection usinguseGetListwithfilter: { [optionValue]: currentValue }
// fetch current value
const {
referenceRecord: currentReferenceRecord,
refetch: refetchReference,
error: errorReference,
isLoading: isLoadingReference,
isFetching: isFetchingReference,
isPending: isPendingReference,
} = useReference<RecordType>({
id: currentValue,
reference,
// @ts-ignore the types of the queryOptions for the getMAny and getList are not compatible
options: {
enabled: currentValue != null && currentValue !== '',
meta,
...otherQueryOptions,
},
});
Another issue is that sometimes values stored in current table's owner attribute are not found in users.login table (due to data retention issues). When that happens, the drop-down box will be empty.
If a referenced value is still missing from allChoices and availableChoices, can we add { [optionValue]: currentValue } to these variables, so we can display invalid values as selected?
This is explained in the FAQ: https://marmelab.com/react-admin/FAQ.html#can-i-have-custom-identifiersprimary-keys-for-my-resources.
@djhi , I understand that I can rename the id attribute at the data provider level; however, this is not an ideal solution. My users table already has an id field that is widely used throughout the application. However, in some cases, the simplest approach is to use users.login as a foreign key instead of users.id (we have situations when data arrives from 3rd party systems and includes login instead of id)
Moreover, it appears that the React-Admin team anticipated such use cases, as the AutocompleteInput component includes an optionValue parameter.
What I’m requesting is to extend this capability to the ReferenceInput component. This would be logical since ReferenceInput and AutocompleteInput are designed to work together; however integration between these components breaks if AutocompleteInput.optionValue is used
Would it be possible to reopen the issue?
I have provided a code sandbox to demonstrate the issue:
https://codesandbox.io/p/github/marmelab/react-admin-sandbox/csb-7wk6kf/draft/nifty-blackwell?file=%2Fsrc%2Fcomments%2FCommentEdit.tsx%3A151%2C1-173%2C32
I've added 2 AutocompleteInput components, referencing authors1 and authors2 tables (see below)
when I navigate to https://7wk6kf-8080.csb.app/#/comments/2, I see that the first drop-down box does not show a value, since it was not fetched
<ReferenceInput
source="author.name"
reference="authors1"
page={1}
perPage={2}
queryOptions={{ refetchOnWindowFocus: false, retry: false }}
>
<AutocompleteInput
optionValue="name" //
/>
</ReferenceInput>
<ReferenceInput
source="author.name"
reference="authors2"
page={1}
perPage={50000000}
queryOptions={{ refetchOnWindowFocus: false, retry: false }}
>
<AutocompleteInput
optionValue="name" //
/>
</ReferenceInput>
authors1: [
{ id: 1, name: "Justina Hegmann" },
{ id: 2, name: "Ms. Brionna Smitham MD" },
{ id: 3, name: "Edmond Schulist" },
{ id: 4, name: "Danny Greenholt" },
{ id: 5, name: "Luciano Berge" },
{ id: 6, name: "Kiley Pouros" },
{ id: 7, name: "Annamarie Mayer" },
{ id: 8, name: "Breanna Gibson" },
{ id: 9, name: "Logan Schowalter" },
],
authors2: [
{ id: 1, name: "Justina Hegmann" },
{ id: 2, name: "Ms. Brionna Smitham MD" },
{ id: 3, name: "Edmond Schulist" },
{ id: 4, name: "Danny Greenholt" },
{ id: 5, name: "Luciano Berge" },
{ id: 6, name: "Kiley Pouros" },
{ id: 7, name: "Annamarie Mayer" },
{ id: 8, name: "Breanna Gibson" },
{ id: 9, name: "Logan Schowalter" },
],
Hi @panfiva , Thank you for this additional information.
The optionValue prop was introduced because AutocompleteInput can also be used on local data. But when fetching from the API, we consider it's the dataProvider's responsibility to transform the data into the format expected by React Admin.
If you need to transform the data only for a specific call, you can pass a specific meta option in the queryOptions to let the dataProvider know.
However I'll reopen the issue and mark it as a documentation enhancement, as we should probably explain that in the documentation. Thanks for reporting the issue in any case!