Search code examples
javascriptreactjsmaterial-uiformikformik-material-ui

Material UI AutoComplete React. Display different options in list and save different option in form state (with multiple values)


I intend to use Autocomplete such that it stores a certain property of an object in the form state and displays a different property in the autocomplete option list. For example, if the option list is as follows:

[
    { gender_name_short: "F", gender_name_long: "Female" },
    { gender_name_short: "M", gender_name_long: "Male" },
    { gender_name_short: "O", gender_name_long: "Other" }
]

I intend to store gender_name_short in the form state and display gender_name_long in the dropdown list. I was able to achieve this and here is the codesandbox link for the implementation I did (Can you also suggest a better way?) https://codesandbox.io/s/cool-bogdan-6lyxs?file=/src/App.js:231-412

Now my issue is that I want to also be able to store multiple values in an array,not applicable in this example as when person cannot have multiple genders, but I would like to use it for other use cases. So how should I go about doing that

Current Behavior 😯

If I add the 'multiple' prop to the Autocomplete component i get the error TypeError Cannot read property 'filter' of undefined

Expected Behavior 🤔

stores the multiple values in an array in its respective short_name_format eg) ['M','F','O']

Steps to Reproduce 🕹

https://codesandbox.io/s/cool-bogdan-6lyxs?file=/src/App.js:231-412 Steps:

  1. Currently the code works without multiple to give a demo of what works
  2. Un-comment multiple in App.js in Autocomplete call (prop)
  3. Change the initialisation of gender to an empty list

Solution

  • This sandbox shows a possible solution to your problem.

    Checkout the transformValue util I've added at the top of FormikAutocomplete.js:

    const tranformValue = (value, fieldtosave) =>
      Array.isArray(value)
        ? value.map(v => v[fieldtosave] || v)
        : value[fieldtosave];
    

    And its usage:

    <Autocomplete
          onChange={(_, value) =>
            setFieldValue(name, value ? tranformValue(value, fieldtosave) : null)
          }
     ...
    />
    

    Basically, what you were missing is that when the Autocomplete is set to multiple the onChange value is an array.