How to select default option in Material-UI Autocomplete component dynamically? - reactjs

I am looking for a way to pre-set a default option in a Autocomplete component, just when the ajax call completes loading the list of options.
So the use case would be this: when the user opens the page, in the background a list of options would be loaded into state from the ajax response. I want to select the first retrieved option from the list, as soon as it gets loaded. Currently, I just have a basic way to offer a list of options:
<Autocomplete
options={defaultProps.options}
getOptionLabel={option => option.name}
renderInput={params => (
<TextField {...params} variant="outlined" fullWidth />
)}
/>
but don't know to select the first one when it gets loaded.

I'm using useEffect to demonstrate an ajax request on component mount.
You can use the value property to set the value after the component has been rendered.
While waiting for the ajax request to resolve, you can use the loading prop to change the component mode to loading
const [options, setOptions] = useState([]);
const [def, setDef] = useState(null);
useEffect((()=>{
setTimeout(()=>{
const tempArr = [{name:'Subject'},{name:'Another Subject'}];
setOptions(tempArr);
setDef(tempArr[0]);
}, 1000);
}), []);
return (
<div className="App">
<h1>Autocomplete</h1>
{<Autocomplete
options={options}
loading={!def}
value={def}
getOptionLabel={option => option.name}
renderInput={params => (
<TextField {...params} variant="outlined" fullWidth />
)}
/>}
</div>
);

In latest version of Material UI theres an autoHighlight prop.
<Autocomplete
options={defaultProps.options}
getOptionLabel={option => option.name}
renderInput={params => (
<TextField {...params} variant="outlined" fullWidth />
)}
autoHighlight // add this
/>
See the API for Autocomplete

Related

Material UI Autocomplete: Display part of selection

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}
...
/>

How to prevent re-render while keeping state when using Material UI Autocomplete with multiple options?

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.

React material UI autocomplete is not working with the formik

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/

How to disable filtering options in material-ui Autocomplete?

I'm using material-ui Autocomplete. When the user changes input, it fetches suggestions from a backend asynchronously. This is part of the code:
const [options, setOptions] = useState([]);
<Autocomplete
...
freeSolo={true}
options={options}
renderInput={params => (
<TextField
...
{...params}
onChange={async (e) => {
// get suggestions from backend
const suggestions = await getSuggestions(e.target.value);
// update autocomplete options
setOptions(suggestions);
...
}}
InputProps={{
...params.InputProps,
endAdornment: (
<React.Fragment>
{loading ? <CircularProgress color="inherit" size={20} /> : null}
{params.InputProps.endAdornment}
</React.Fragment>
),
}}
/>
)}
/>
The problem is that material-ui Autocomplete doesn't show all of the options that are set using "setOptions". It filters them.
for example: Suppose that the user enters "appl" and getSuggestions returns ["apple", "orange", "potato"]. But It only shows "apple" because it filters out "orange" and "potato".
How can I disable filtering?
The filterOptions method is intended to give you the freedom to decide which options will be available and which will be hidden.
If you just want to show all options - just implement the filterOptions to return all the values:
filterOptions={(options, state) => options}

Clear all selected values from material-ui Autocomplete Combo box

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?.

Resources