Material-ui: [Autocomplete] Triggers change event twice with "enter"

Created on 13 Nov 2019  路  8Comments  路  Source: mui-org/material-ui

  • [ ] The issue is present in the latest release.
  • [ ] I have searched the issues of this repository and believe that this is not a duplicate.

Current Behavior 馃槸

I have used Autocomplete with FreeSolo prop, but I have a problem. when I have typed the word in the textfield / input and then I press Enter, the textfield becomes blank (deleted text). What I want, the word doesn't disappear when I press enter, how do I fix this?

<Autocomplete freeSolo id="combo-box-demo" options={top100Films} getOptionLabel={option => option.title} style={{ width: 300 }} renderInput={params => ( <TextField {...params} label="Combo box" variant="outlined" fullWidth /> )} />
https://codesandbox.io/s/material-demo-k1uyh

Expected Behavior 馃

If I type text in the textfield and then I press Enter, the text should not be lost or not deleted

Your Environment 馃寧

| Tech | Version |
| ----------- | ------- |
| Material-UI | v4.6.1 |
| React | 16.11.0 |
| @material-ui/lab | ^4.0.0-alpha.32 |

bug 馃悰 Autocomplete good first issue

Most helpful comment

@setyawanandik Thank you for the feedback. Your codesandbox is invalid, see the error it reports. When you set freeSolo to true, the user can pick a string value. Unless you adapt the value to match the exisiting options, you need to tell getOptionLabel how to handle the new shape:

    <Autocomplete
      freeSolo
      options={[{ title: 'foo' }]}
-     getOptionLabel={option => option.title}
+     getOptionLabel={option => typeof option === 'string' ? option : option.title}

However, there is an interesting wrong behavior I haven't anticipated that surface here. The Enter key shouldn't trigger a new onChange event if its already currently selected. This can be solved with:

diff --git a/packages/material-ui-lab/src/useAutocomplete/useAutocomplete.js b/packages/material-ui-lab/src/useAutocomplete/useAutocomplete.js
index ba7dcb7e4..2723e2648 100644
--- a/packages/material-ui-lab/src/useAutocomplete/useAutocomplete.js
+++ b/packages/material-ui-lab/src/useAutocomplete/useAutocomplete.js
@@ -531,7 +531,7 @@ export default function useAutocomplete(props) {
           // We don't want to validate the form.
           event.preventDefault();
           selectNewValue(event, filteredOptions[highlightedIndexRef.current]);
-        } else if (freeSolo && inputValue !== '') {
+        } else if (freeSolo && inputValueFilter !== '') {
           selectNewValue(event, inputValue);
         }
         break;

Do you want to work on this problem? We would need to add a test case as it's subtle.

All 8 comments

i think this problem of getOptionLabel

<Autocomplete
     freeSolo
     id="combo-box-demo"
     options={top100Films}
     getOptionLabel={option => option.title}
     style={{ width: 300 }}
     renderInput={params => (
       <TextField {...params} label="Combo box" variant="outlined" fullWidth />
     )}
   />

if enter:

index.js:1 Material-UI: the `getOptionLabel` method of useAutocomplete do not handle the options correctly.
The component expect a string but received undefined.
For the input option: "11111111231", `getOptionLabel` returns: undefined. 
    in Autocomplete (created by WithStyles(ForwardRef(Autocomplete)))
    in WithStyles(ForwardRef(Autocomplete)) (at pages/鈥媔ndex.js:253)
    in Index (created by WithStyles(Index))
    in WithStyles(Index) (at _app.js:37)
    in MyApp

### But work and no error if use

<Autocomplete
     freeSolo
     id="combo-box-demo"
     options={top100Films.map(option => option.title)}
     style={{ width: 300 }}
     renderInput={params => (
       <TextField {...params} label="Combo box" variant="outlined" fullWidth />
     )}
   />

or

<Autocomplete
     freeSolo
     id="combo-box-demo"
     options={top100Films}
     getOptionLabel={option => option.title?option.title:option}
     style={{ width: 300 }}
     renderInput={params => (
       <TextField {...params} label="Combo box" variant="outlined" fullWidth />
     )}
   />

Is your autoComplete component accepting all the inputs you have given in text field, cause when i am trying to give for example asd as input its showing like this.
image

@setyawanandik Thank you for the feedback. Your codesandbox is invalid, see the error it reports. When you set freeSolo to true, the user can pick a string value. Unless you adapt the value to match the exisiting options, you need to tell getOptionLabel how to handle the new shape:

    <Autocomplete
      freeSolo
      options={[{ title: 'foo' }]}
-     getOptionLabel={option => option.title}
+     getOptionLabel={option => typeof option === 'string' ? option : option.title}

However, there is an interesting wrong behavior I haven't anticipated that surface here. The Enter key shouldn't trigger a new onChange event if its already currently selected. This can be solved with:

diff --git a/packages/material-ui-lab/src/useAutocomplete/useAutocomplete.js b/packages/material-ui-lab/src/useAutocomplete/useAutocomplete.js
index ba7dcb7e4..2723e2648 100644
--- a/packages/material-ui-lab/src/useAutocomplete/useAutocomplete.js
+++ b/packages/material-ui-lab/src/useAutocomplete/useAutocomplete.js
@@ -531,7 +531,7 @@ export default function useAutocomplete(props) {
           // We don't want to validate the form.
           event.preventDefault();
           selectNewValue(event, filteredOptions[highlightedIndexRef.current]);
-        } else if (freeSolo && inputValue !== '') {
+        } else if (freeSolo && inputValueFilter !== '') {
           selectNewValue(event, inputValue);
         }
         break;

Do you want to work on this problem? We would need to add a test case as it's subtle.

@oliviertassinari - I experienced the same issue, but am not using freeSolo. I used your getOptionLabel workaround getOptionLabel={option => typeof option === 'string' ? option : option.title} & that worked for me in MUI: 4.6.1 & lab: 4.0.0-alpha.32.

I used the combo box example straight off the site with my dataset which is just an array of { label: "bla", value: "bla" }

<Autocomplete
  id="combo-box-demo"
  options={top100Films}
  getOptionLabel={option => option.title}
  style={{ width: 300 }}
  renderInput={params => (
    <TextField {...params} label="Combo box" variant="outlined" fullWidth />
  )}
/>

I encounter the same issue with freeSolo configuration. Is this a really good decision to set typed in text directly as selected option on Enter? This makes option typing a bit confusing, as we have an adapter to convert arbitrary option value to displayable text, but nothing to perform counter-action. Maybe it makes sense to introduce a property which can hold a function to convert free-form user input to option type?

I can try and work on a test case for this @oliviertassinari if no one else has started on one.

@tplai Awesome, you are free to go :)

Maybe it makes sense to introduce a property which can hold a function to convert free-form user input to option type?

@gmltA This should already be possible by controlling the value prop.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

sys13 picture sys13  路  3Comments

anthony-dandrea picture anthony-dandrea  路  3Comments

revskill10 picture revskill10  路  3Comments

ericraffin picture ericraffin  路  3Comments

newoga picture newoga  路  3Comments