Solution
I used renderTags in my Autocomplete:
renderTags={() => (
<div>
{(props.selectedAutocompleteValues).map(value => (
<Chip key={value} label={value} />
))}
</div>
)}
Original question
I'm trying to add a handler that clears all selected values from an Autocomplete with multiple values and a dropdown. Basicly duplicating the action of the clear-button that is inside the Autocomplete, and triggering this action from outside the Autocomplete.
The reason for this is that I want to have a filter (material-ui Select) that allows reduces the number of options in the Autocomplete. When changing the filter-value, the previously selected values of the Autocomplete should be cleared.
I'm rendering the values in the Autocomplete with the following code, so it seems like what I need to do is change the params in some way. Any suggestions on how to do this, or other ways of clearing the values?
renderInput={params => (
<TextField {...params} label="my-label" variant="outlined" fullWidth />
)}
Update after comment from Ryan Cogswell:
<Autocomplete
multiple
disableCloseOnSelect
autoHighlight
clearText='Nullstill'
closeText='Lukk'
openText='Åpne'
options={Array.from(props.myMap.keys())}
onChange={(event: any, value: string) => {
props.myUpdateFunction(value)
}}
renderInput={params => (
<TextField {...params} label="myLabel" variant="outlined" fullWidth />
)}
/>
where myUpdateFunction is in the grandparent-component of where the Autocomplete is:
myUpdateFunction = (myArray: Array<string>) => {
this.setState({
selectedAutocompleteValues: myArray,
})
}
The Select component that I want to use to reset the Autocomplete component:
<Select
labelId="my-select-label"
id="my-select"
autoWidth
value={props.mySelectValue}
onChange={(event: any) => props.updateSelect(event.target.value)}>
{Array.from(props.selectOptions, ([optionNr, optionName]) =>
<MenuItem key={optionNr} value={optionNr}>{optionName}</MenuItem>
)}
</Select>
with the following onChange handler:
updateFylke = (value: number) => {
const selectedAutocompleteValues = new Array<string>();
this.setState({
mySelectValue: value,
selectedAutocompleteValues: selectedAutocompleteValues,
})
}
I recommend using a controlled input approach (i.e. specify the value prop for the Autocomplete using selectedAutocompleteValues). Then clearing the Autocomplete is just a matter of updating your state appropriately.
You can see an example of this approach in this related answer: Material ui Autocomplete: can tags be created on events aside from 'Enter' events?.
Related
What's happening is on page load, the: form.values.statistics?.ethnicity generates the Chips fine but doesn't set the selected values in the Autocomplete component.
Like in the image below, the Caucasian appears to be not selected when it should be selected from the Autocomplete component
What I've thought of and tried so far in which data.data.attributes.statistics.ethnicity === form.values.statistics.ethnicity:
Maybe I'm missing the "name" property from the Autocomplete component - tried adding so, but I can't. It says the property doesn't exist for the component. Which is weird?
value={ethnicityOptions[arrayOfSelectedIds]} or value={ethnicityOptions[data.data.attributes.statistics.ethnicity]}
Autocomplete code:
<Autocomplete
multiple
options={ethnicityOptions}
getOptionLabel={(ethnicityOptions) => ethnicityOptions.name}
id="multiple-tags"
value={form.values.statistics?.ethnicity}
onChange={(e, newValue) => {
form.setFieldValue('statistics.ethnicity', newValue);
form.handleChange(e);
}}
renderTags={() => null}
renderInput={(params) => (
<Grid className={classes.autoCompleteGrid}>
<TextField
{...params}
variant="outlined"
onChange={form.handleChange}
placeholder="Ethnicities"
/>
</Grid>
)}
/>
Code for generating Chips:
{form.values.statistics?.ethnicity
? form.values.statistics?.ethnicity?.map((v) => (
<Chip
key={v.name}
label={v.name}
onDelete={() => {
onEthnicityChipDelete(v);
}}
/>
))
: ''}
I'm currently stuck on this and I might be just missing something. Any help to breakthrough would be really appreciated!
I was using previous Mui version 4.11.4 with the Autocomplete component and everything worked well with the disablePortal prop.
However, i am using Mui 5 now and the autocomplete dropdown list sometimes show on top instead of always being on the bottom as what i wanted.
<Autocomplete
disablePortal={true}
id='controlled-demo'
ref={idRef}
name={id.current}
onChange={(e, value) => {
const id = idRef.current.getAttribute('name');
handleOptionChange(e, value, id);
}}
options={getExercisesByCategoryAndMusclegroup(exercise)}
getOptionLabel={(option) => `${option.title}`}
isOptionEqualToValue={(option, value) => option.title === value.title}
renderInput={(params) => (
<TextField
{...params}
name='exercise'
// onChange={(e, value) => handleOptionChange(e, value)}
label='Search exercise...'
variant='outlined'
size={isMatched ? 'small' : 'medium'}
/>
)}
/>
I've tried using a custom Popper component as i saw on another post setting the placement to 'bottom' but that didnt resolve my issue.
Is there a bug to the new v5? Anyone else is experiencing this?
I don't know if this is a bug in MUI v5, but what worked for me is to simply remove the disablePortal prop, which automatically set the placement of the dropdown list to the bottom for any number of elements in the list.
I'm displaying three property values (option.primary_line, option.city, option.state, and option.zip_code) from state in the autocomplete suggestions; however, I'm trying to display only the option.primary_line value in the textarea when an option from the list is selected. I've tried setting the option.primary_line value to state and adding it as a value (tried defaultValue as well) to the textarea to no avail. What am I missing?
<Autocomplete
id="combo-box-demo"
options={addressSuggestions}
getOptionLabel={(option) =>
`${option.primary_line}, ${option.city}, ${option.state} ${option.zip_code}`
}
onInputChange={handleAddressLookup}
freeSolo={true}
renderInput={(params) => (
<TextField
{...params}
variant="outlined"
fullWidth
/>
)}
/>
You should use renderOption instead, and in getOptionLabel return the value you want to be assigned to the input
<Autocomplete
...
renderOption={(option) =>
`${option.primary_line}, ${option.city}, ${option.state} ${option.zip_code}`
}
getOptionLabel={(option) => option.primary_line}
...
/>
I am using Material UI's Autocomplete component with multiple options enabled. I need to be able to select multiple options and update the state every time the value changes. For this, I am using the onChange prop. This works fine when using only one option. But with multiple options enabled, every time I select an option, the component re-renders and I am unable to select a second option.
This is the onChange handler:
const handleUserAssignEvent = (event, value) => {
setSelectedUsers(value)
}
This is the Autocomplete component:
const renderUserAssignmentForm = () => {
const icon = <CheckBoxOutlineBlankIcon fontSize="small" />
const checkedIcon = <CheckBoxIcon fontSize="small" />
return (
<Autocomplete
multiple
id="usersList"
options={filteredUsers ?? users ?? []}
noOptionsText="No users found..."
disableCloseOnSelect
onChange={(event, value) => handleUserAssignEvent(event, value)}
getOptionLabel={(option) => option.fullname}
renderOption={(option, { selected }) => (
<>
<Checkbox
icon={icon}
checkedIcon={checkedIcon}
style={{ marginRight: 8 }}
checked={selected}
/>
{option.fullname}
</>
)}
style={{ width: 500 }}
renderInput={(params) => (
<TextField
{...params}
variant="outlined"
label="Users"
placeholder="User lookup..."
/>
)}
/>
)}
What can I do to be able to update the state without having the Autocomplete component re-render on every change and be able to select multiple options?
I've replicated your example here and there was no problem with selecting multiple options.
Your problem might be that the options prop filteredUsers and users are related/change with selectedUsers.
Or the whole component which contains renderUserAssignmentForm being unmounted and mounted again.
I have this code snippet, which is written by someone else.
<FormControl className={classes.formControl}>
<InputLabel id="combo-box-demo">
{values.type === "forAllCustomers" ? "" : ""}
</InputLabel>
<Autocomplete
id="combo-box-demo"
name="customerId"
onBlur={handleBlur}
onChange={handleChange}
value={values.customerId}
options={agents}
getOptionLabel={(option) => option.name}
disabled={values.type === "forAllCustomers"}
renderTags={(value, getTagProps) => {
filteredAgents(values.type).map(
(option, agentId) => (
<Chip
variant="outlined"
label={option.name}
// size="small"
{...getTagProps({ agentId })}
/>
)
);
}}
renderInput={(params) => (
<TextF
{...params}
variant="outlined"
label="Customer"
placeholder="Select"
name="agentId"
/>
)}
/>
</FormControl>
Here we load bunch of agents. If user pick one agent, that agents id should set as the customerId.
Here we use formik, so onBlur={handleBlur} onChange={handleChange} is controlled by the formik.
I tried by setting value to values.customerId But it seems not working and also I am getting an error in the console saying
index.js:1 Material-UI: The getOptionLabel method of Autocomplete
returned undefined instead of a string for "".
How do I fix this issue?
Anyhelp!
Thanks in advance. =)
See, the signature of the function onChange of AutoComplete is:
function(event: object, value: T | T[], reason: string) => void
However, signature of handleChange of Formik is
handleChange: (e: React.ChangeEvent<any>) => void
The problem is that simply passing onChange={handleChange} will not do what you think.
See, if you put, before the return statement a console.log(values), you'll see your initialValues object. However, a change in the Autocomplete will fill this object with strange combo-box-demo-option-0 1, 2 and so on. This is because how the Autocomplete component handles the combobox and the name and id properties. According to Formik, handleChange will look for the name or id to operate, and none have the correspondence you want.
Enough said, to fix your problem, you have to use another method provided by Formik: setFieldValue
Your Autocomplete should look something on the lines of:
<Autocomplete
id="combo-box-demo"
name="customerId"
onChange={(e, v) => {
setFieldValue("name", v?.name || "");
setFieldValue("customerId", v?.id || "");
}}
value={values}
options={agents}
getOptionLabel={(option) => option.name || ''}
style={{ width: 300 }}
renderInput={(params) => (
<TextField {...params} label="Combo box" variant="outlined" />
)}
/>;
You will not need the useState because you are not handling yourself any state changes. A regular javascript object will be enough.
Please check the agents you are getting. There might be an issue with your agents data coming from API RESPONSE or from anywhere else. According to Material-UI, the parameter you pass to options should be in an Array but your one might be an Object.
Please convert the Data type of agents to Array instead of Object if it is not in an Array and it will work!
<Autocomplete
id="combo-box-demo"
name="customerId"
onBlur={handleBlur}
onChange={handleChange}
value={values.customerId}
options={agents} //This should be in An Array
getOptionLabel={(option) => option.name} //Then access name
disabled={values.type === "forAllCustomers"}
/>
Please check the Official Docs of Material-UI https://material-ui.com/components/autocomplete/