'Handle change on Autocomplete Component from material ui
I want to use Autocomplete
component for input tags. I'm trying to get the tags and save them on a state so I can later save them on the database. I'm using functions instead of classes in react. I did try with onChange
, but I didn't get any result.
<div style={{ width: 500 }}>
<Autocomplete
multiple
options={autoComplete}
filterSelectedOptions
getOptionLabel={(option) => option.tags}
renderInput={(params) => (
<TextField
className={classes.input}
{...params}
variant="outlined"
placeholder="Favorites"
margin="normal"
fullWidth
/>
)}
/>
</div>;
Solution 1:[1]
As Yuki already mentioned, make sure you did use the onChange
function properly. It receives two parameters. According to the documentation:
Signature:
function(event: object, value: any) => void
.
event
: The event source of the callback
value
: null (The value/values within the Autocomplete component).
Here's an example:
import React from 'react';
import Chip from '@material-ui/core/Chip';
import Autocomplete from '@material-ui/lab/Autocomplete';
import TextField from '@material-ui/core/TextField';
export default class Tags extends React.Component {
constructor(props) {
super(props);
this.state = {
tags: []
};
this.onTagsChange = this.onTagsChange.bind(this);
}
onTagsChange = (event, values) => {
this.setState({
tags: values
}, () => {
// This will output an array of objects
// given by Autocompelte options property.
console.log(this.state.tags);
});
}
render() {
return (
<div style={{ width: 500 }}>
<Autocomplete
multiple
options={top100Films}
getOptionLabel={option => option.title}
defaultValue={[top100Films[13]]}
onChange={this.onTagsChange}
renderInput={params => (
<TextField
{...params}
variant="standard"
label="Multiple values"
placeholder="Favorites"
margin="normal"
fullWidth
/>
)}
/>
</div>
);
}
}
const top100Films = [
{ title: 'The Shawshank Redemption', year: 1994 },
{ title: 'The Godfather', year: 1972 },
{ title: 'The Godfather: Part II', year: 1974 },
{ title: 'The Dark Knight', year: 2008 },
{ title: '12 Angry Men', year: 1957 },
{ title: "Schindler's List", year: 1993 },
{ title: 'Pulp Fiction', year: 1994 },
{ title: 'The Lord of the Rings: The Return of the King', year: 2003 },
{ title: 'The Good, the Bad and the Ugly', year: 1966 },
{ title: 'Fight Club', year: 1999 },
{ title: 'The Lord of the Rings: The Fellowship of the Ring', year: 2001 },
{ title: 'Star Wars: Episode V - The Empire Strikes Back', year: 1980 },
{ title: 'Forrest Gump', year: 1994 },
{ title: 'Inception', year: 2010 },
];
Solution 2:[2]
I needed to hit my api on every input change to get my tags from backend!
Use Material-ui onInputChange if you want to get your suggested tags on every input change!
this.state = {
// labels are temp, will change every time on auto complete
labels: [],
// these are the ones which will be send with content
selectedTags: [],
}
}
//to get the value on every input change
onInputChange(event,value){
console.log(value)
//response from api
.then((res) => {
this.setState({
labels: res
})
})
}
//to select input tags
onSelectTag(e, value) {
this.setState({
selectedTags: value
})
}
<Autocomplete
multiple
options={top100Films}
getOptionLabel={option => option.title}
onChange={this.onSelectTag} // click on the show tags
onInputChange={this.onInputChange} //** on every input change hitting my api**
filterSelectedOptions
renderInput={(params) => (
<TextField
{...params}
variant="standard"
label="Multiple values"
placeholder="Favorites"
margin="normal"
fullWidth
/>
Solution 3:[3]
Are you sure you used onChange
correctly?
onChange
signature: function(event: object, value: any) => void
Solution 4:[4]
I wanted to update my state when I select an option from the autocomplete. I had a global onChange handler that manages for all inputs
const {name, value } = event.target;
setTukio({
...tukio,
[name]: value,
});
That updates the object dynamically based on the name of the field. But on the Autocomplete the name returns blank. So I changed the handler from onChange
to onSelect
. Then either create a separate function to handle the change or as in my case added an if statement to check if the name is not passed.
// This one will set state for my onSelect handler of the autocomplete
if (!name) {
setTukio({
...tukio,
tags: value,
});
} else {
setTukio({
...tukio,
[name]: value,
});
}
The above approach works if u have a single autocomplete. If you have multiple u can pass a custom function like below
<Autocomplete
options={tags}
getOptionLabel={option => option.tagName}
id="tags"
name="tags"
autoComplete
includeInputInList
onSelect={(event) => handleTag(event, 'tags')}
renderInput={(params) => <TextField {...params} hint="koo, ndama nyonya" label="Tags" margin="normal" />}
/>
// The handler
const handleTag = ({ target }, fieldName) => {
const { value } = target;
switch (fieldName) {
case 'tags':
console.log('Value ', value)
// Do your stuff here
break;
default:
}
};
Solution 5:[5]
@Dworo
For anyone that has a problem with displaying a selected item from the dropdown in the Input field.
I found a workaround. Basically, you have to bind an inputValue
at onChage
for both Autocomplete
and TextField
.
const [input, setInput] = useState('');
<Autocomplete
options={suggestions}
getOptionLabel={(option) => option}
inputValue={input}
onChange={(e,v) => setInput(v)}
style={{ width: 300 }}
renderInput={(params) => (
<TextField {...params} label="Combo box" onChange={({ target }) => setInput(target.value)} variant="outlined" fullWidth />
)}
/>
Solution 6:[6]
This worked for me:
I have an array of objects of type:
{
id: someId,
label: someLabel,
}
let's call this array "items". And use a formState object, like this:
const [formState, setFormState] = useState({
idPuntoVenta: '',
nomPuntoVenta: '',
selected: items[0],
});
And defined the Autocomplete component like this:
<Autocomplete
disablePortal
id="salesPoint"
options={sortedSalesPoints}
value={selected}
onChange={(event, newValue) => {
setFormState({
...formState,
selected: newValue,
idPuntoVenta: newValue?.id,
});
}}
inputValue={nomPuntoVenta}
onInputChange={(event, newInputValue) => {
setFormState({
...formState,
nomPuntoVenta: newInputValue,
});
}}
renderInput={(params) => (
<TextField
{...params}
className="form-control"
size="small"
label="Punto de venta"
required
/>
)}
/>;
The important thing here (and the one that took me a while) is to understand that the {value} property of the Autocomplete component is an object of the same type of the ones stored in the array "items"
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Community |
Solution 2 | |
Solution 3 | Yuki |
Solution 4 | TRANS |
Solution 5 | |
Solution 6 | Ricardo Álvarez |