Search code examples
formslistfilterviewreact-admin

ReferenceInput Select Input for Filter component Form


I built a custom Filter component for my List View and Im having trouble populating a Select Input of ALL available options for a property. for instance

<Form onSubmit={onSubmit} initialValues={filterValues} >
    {({ handleSubmit }) => (
       <form onSubmit={handleSubmit}>
          <ReferenceInput label="Ring Id" source="ringid" reference="candidates">
              <SelectInput optionText="ringid" />
          </ReferenceInput>
       </form>
     )}
</Form>

Without building a "getMany" dataProvider Im told that I can access all of the (2,000+ ids) "ringid"s pulled in from the "getList" provider and list every ID into the SelectInput field and search in my custom Filter component.

Issues presented:

  1. I have to hard code amount of results I can have (Default 25)
  2. When I submit the form to Search through the filter component "Associated reference no longer appears to be available." appears and the search fails.
  3. The "getMany" component is only half way built but it seems that ReferenceInput only wants to use "getMany"(Im told that building the backend and building code to use getMany is not an priority to build so I cant build it myself)

25 Populated IDs Screenshot

Form Error when Filter is submitted ScreenShot

So I would like some help in the right direction to populate a SelectInput of all available ids in the getList dataProvider and be sure that I can even use this input in my Filter form component. Thank you in advance for any feedback.


Solution

  • 1: Yes, i think there's no option to add pagination to ReferenceInput, you must hardcode it, but, if your backend already supports text search, you can use an AutocompleteInput as child, allowing users to filter results:

    <ReferenceInput 
         label="Ring Id" 
         source="ringid" 
         reference="candidates"
         filterToQuery={searchText => ({ paramNameThatYourBackendExpects: searchText })}
    >
        <AutocompleteInput optionText="ringid" />
    </ReferenceInput>
    

    2 & 3: 2 happens because of 3. ReferenceInput only "wants" to use getMany because it also support SelectManyInput as child, for such case, it's better to get all selected options at once, than calling one by one, so, to make code simpler, ReferenceInput always use getMany. If you can't implement backend part of getMany, but can add code to your dataProvider, you can implement getMany by making multiple getOne calls:

    Assuming a v3 dataProvider:

    this.getMany = async (resource, params) => {
    
        const response = {data: []}
    
        for (const id of params.id) {
            response.data.push(await this.getOne(resource, {id}))
        }
    
        return response
    }
    

    v2 is implementation-dependant, just follow the same principle.

    If you can't change the dataProvider, e.g, a third-party available dataProvider, you can wrap it:

    v3

    const fakeGetManyDataProvider = dataProvider => ({
        ...dataProvider,
        getMany: async (resource, params) => {
            const response = {data: []}
    
            for (const id of params.id) {
                response.data.push(await dataProvider.getOne(resource, {id}))
            }
    
            return response
        }
    })
    

    v2

    import { GET_MANY, GET_ONE } from 'react-admin'
    
    const fakeGetManyDataProvider = dataProvider => async (verb, resource, params) => {
        if (verb === GET_MANY) {
                const response = {data: []}
    
                for (const id of params.id) {
                    response.data.push(await dataProvider(GET_ONE, resource, {id}))
                }
    
                return response
        }
        return dataProvider(verb, resource, params)
    }
    

    Please note that error handling is omitted for simplicity, react admin expects rejecteds promise instead of unhandled expections, so you must handle errors.