-
-
Notifications
You must be signed in to change notification settings - Fork 32.4k
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
[Autocomplete] Support values other than raw options #23708
Comments
This comment has been minimized.
This comment has been minimized.
Forcing the developer to manually manage the values list doesn't feel like a great alternative. Using Select, TextField, etc... isn't this complex even when using the
You mean store Honestly it feels wrong to have localized labels in form data just because of limitations in useAutocomplete's implementation. And MUI doesn't work this way with any other field. Select, Radio, and Checkbox can easily be connected to form handling code and all support using a separate value and label for options. It doesn't feel right that if you have a Select implemented that way (with the same simple submit handler code as the rest of your fields) and it becomes too long to be a normal select, you have to rewrite the submit handler code to work differently than every other field, just because the field type used changed from Select to Autocomplete. |
We have a similar pain in this direction on #21489. Ok, why not. we could:
Feel free to work on it. At least, we have spotted a small issue with the generated documentation. |
Could I try and take a wack at this? |
Hi! I'm completely new to open source contributions so I'm a bit confused, wouldn't this just be a one line change? Where we just add,
to Autocomplete.js I'm thinking since getOptionValue is a completely new function, nothing depends on it so all I would need to add is the function itself and a test. Please correct me if I'm wrong, thank you so much! |
@ZovcIfzm If you are completely new, you might want to do one "good first issue" before moving to this "goo to take" issue. Regarding your question. Yes, we would need a new test case, to make sure it has the correct impacts on the component, e.g. change the onChange returned value, change how value <-> option comparison is done, etc. |
Thank you! Looking at the issue more in-depth I realize it might be out of my scope. I don't quite understand how to change the onChange returned value for example or what you mean by change how value <-> option comparison is done. I'll go and try to tackle a different issue. |
Investigating this a bit more, this actually requires a breaking change to the UseAutocompleteProps/AutocompleteProps types. Right now we have So we'll need to change |
@dantman option and value should keep the same type. I don't think that it's OK to allow them to diverge. How about we only do #23708 (comment)? Keeping value and options with the same type? |
That's the whole point of this issue. Given But in real-world applications what we actually want is the ability to have If we instead implemented it as If the breaking change is so bad, would it would be better to add a permanent workaround? We could keep |
@dantman I'm not too worried about the branking change but about the mental model it implies. I think that |
That's not the limitation in Autocomplete that triggered this issue. The issue is if you use const [age, setAge] = React.useState('');
const ages = [
{value: '10', label: 'Ten'},
{value: '20', label: 'Twenty'},
{value: '30', label: 'Thirty'},
];
<FormControl className={classes.formControl}>
<InputLabel id="demo-simple-select-label">Age</InputLabel>
<Select
labelId="demo-simple-select-label"
id="demo-simple-select"
value={age}
onChange={(e) => setAge(e.target.value))}
>
{ages.map(age => <MenuItem key={age.value} value={age.value}>{age.label}</MenuItem>)}
</Select>
</FormControl>
<Autocomplete
id="demo-combo-box"
options={ages}
getOptionLabel={(option) => option.label}
getOptionValue={(option) => option.value} // Unless we implement this `age` will be `{value: '10', label: 'Ten'}` instead of "10"
renderInput={(params) => <TextField {...params} label="Age" />}
value={age}
onChange={(e, value) => setAge(value))}
/> |
Which is the behavior react-select implements for the |
Ok, so this isssue is actually a |
From what I understand, it's also not possible with Downshift too. |
I have added the |
@cvburgess So far, we are simply waiting for more developers to upvote the issue. It's the first time a developer reports the pain with react-hook-form or formik, if we have a concrete example on how it would make the integration simpler, I think that it would help. The second incentive for |
For me, I am loading async values from a graphQL API and I have quite a few AutoCompletes in a form, they are used to allow folks to quickly type the value they are looking for (in a list of potentially thousands of options) or scroll to select like a normal dropdown. By using react-hook-form, I need to configure each one to:
It is not a lot of code, but multiply this out times 10 AutoCompletes and it gets to be a lot of duplicate code. I think If my options are objects, I'd expect a simple function to pull out the label, and another to pull out the value and everything should "just work" from there. PS thank you and the team for the hard work over the years. I've used the lib since the v0 days and the support in these github issues has meant so much to the various teams I've worked on. |
Just sharing it here so maybe it helps someone in the future. It's example for wrapper for |
Has anyone come up with a solid implementation of this? Here's my attempt...with a major drawback that any prop that has a generic type must be reconstructed:
But at least now you can do things like this:
And as long as you define the |
@oliviertassinari I can pretty much agree with all cases described here, I have similar issue, but with formik, however issue is still the same:
Which is pretty much identical to #23708 (comment) right I have to work around this by:
using
|
Hi any update on this issue? |
I'm an MUI Pro user and I'm adding onto why this functionality would be useful to me I am building an address input form that I want to use google auto complete to help the user complete the form quickly, but I don't want to add a requirement that the address must be returned by Google and successfully parsed by us to be used. The the first address input field, which should bind to address_line_1, is an autocomplete element which shows google autocomplete address options as the user types. If the user selects one of these options the rest of the is filled out using the place details but they also have the option to just type their full address_line_1 value (and the rest of the form values) manually. This solves the problem of addresses not being found by google / us failing to parse a google address return result into the object expected by the API. In this case, the options of the MUI Autocomplete element are Google Place results, but the value of the autocomplete is a string. If anyone has any advice on implementation for this case it would be appreciated, my currently implementation is very hacky and causes console warnings about the autocomplete value / option mismatch |
Here's my use case: I have a list of widgets:
I want to be able to use an Autocomplete in a form, as an uncontrolled component, and I want to be able to have a default value set. So my options are: 1. Make the label be the value that gets submitted on form submission https://codesandbox.io/s/elated-sanderson-tzfsgc?file=/demo.tsx
I could then do some kind of remapping back to the ID. But that's a pain. 2. I can use getOptionLabel as the 'value' getter, and user 'renderOption' as the label getter. https://codesandbox.io/s/blissful-cray-vcntt6?file=/demo.tsx This almost works, but the problem is that the value will show up in the text field. Also, the search doesn't work.
3. Render tags The renderTags almost solves my problem here (although the search remains a problem). I can use this to render the unfocused textfield value the way I want. However, |
Ok got it! At least for my use case, I can use a hidden input to contain the value, while I still allow the TextField to contain the label value. https://codesandbox.io/s/suspicious-jennings-m22jrf?file=/demo.tsx:1346-1376
|
Doesn't work for me. Hidden input value is being ignored and the entire option object is still being sent. Any updates on this? This sounds more like a bug than a "new feature". Why stop there? Why doesn't it send the entire DOM tree as an input value, for example?.. |
just as quick update, I am sending select options and default values from backend. And just for this type of inputs (select and multiselect), it requires this ugliest "data transformer" workarounds in the form code, which search for option object (from another data source), replaces backend's defaultValue with found option object, to later send it to Autocomplete useController as defaultValue. Which all could be removed with this one prop, holy. |
This is one of the biggest pain points for me every single time I work with MUI forms. Sigh, here we go again. Not sure how many more upvotes we need to make it obvious that :'( |
@oliviertassinari Waiting on this fix (getOptionValue) to be implemented |
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
@oliviertassinari, any update on this? |
Summary 💡
Right now (at least if you use
multiple
) Autocomplete/useAutocomplete thevalue
that comes back inonChange
is always the raw option data. i.e. If you useoptions=[{value: 'a', label: 'A'}, {value: 'b', label: 'B'}]
and select the "A" option then value will be[{value: 'a', label: 'A'}]
.Ideally it would be possible to provide
multiple=true options=[{value: 'a', label: 'A'}, {value: 'b', label: 'B'}]
and get back values like['a']
. Autocomplete does feel like this is intended to be supported, because you can provide agetOptionSelected
and it's used to identify selected options instead of doing any comparisons on the option itself. However when it comes to adding an item to amultiple
array, all useAutocomplete does isnewValue.push(option);
. There is no way to control what part of option is actually used as the value.I think a
getOptionValue(option)
function would fit the current options implementation the most.Examples 🌈
Motivation 🔦
MUI's
<Select>
easily supports this. It uses children instead, so all it takes isoptions.map(item => <MenuItem key={item.value} value={item.value}>{item.value}</MenuItem>)
to do this in Select and pretty much every project I've worked on uses Select this way. It would be strongly preferred if it were easy to use useAutocomplete the same way.The text was updated successfully, but these errors were encountered: