I like the Chip option when multiple is true. Is there an option to enable Chip also when multiple is false ?
<Autocomplete
className={classes.search}
options={top100Films}
getOptionLabel={(option) => option.title}
multiple={false}
renderInput={(params) =>
<TextField {...params}
variant="outlined"
label="Customer's journey"
helperText="Search by: program"
/>}
/>
Thank you
No, unfortunately you would have to change the Autocomplete to a controlled component and do this yourself via the startAdornment prop on the Input. Something like:
function MyAutocomplete() {
const [value, setValue] = useState(null);
const chip = value ?
<Chip label={value.title} onDelete={() => setValue(null)} size="medium" />
: undefined;
return (
<Autocomplete
size="medium"
options={top100Films}
getOptionLabel={(option) => option.title}
onChange={(event, newValue) => setValue(newValue)}
value={value}
renderInput={(params) => (
<TextField
{...params}
InputProps={{
...params.InputProps,
startAdornment: chip
}}
variant="outlined"
label="Customer's journey"
helperText="Search by: program"
/>)}
/>);
}
Demo here
Related
mui autocomplete wont complete the text letter by letter by order its a bit of a mess , someone got a better autocomplete? or knows how to fix ? (example typing "l" will find first "agropoli" than "london")
<Autocomplete
id="free-solo-demo"
freeSolo
options={cityUniqe}
onChange={(event, value) => setSearch(value)}
renderInput={(params) => (
<TextField
{...params}
error={weatherData?.error ? true : false}
fullWidth
label="name your city here..."
value={search}
onChange={(e) => {
setSearch(e.target.value);
}}
ref={inputField}
onKeyDown={(e) => e.key === "Enter" && handleSubmit(e)}
/>
)}
/>
you need to kinda play with the filtration that happens under the hood, Mui provides a createFilterOptions method which you can use as follows:
import { Autocomplete, TextField, createFilterOptions } from "#mui/material";
export default function App() {
// create your filer options here
const filterOptions = createFilterOptions({
matchFrom: "start",
stringify: (option) => option
});
return (
<Autocomplete
id="free-solo-demo"
freeSolo
options={["agropoli", "london", "parlament"]}
filterOptions={filterOptions} // use them here
onChange={(event, value) => setSearch(value)}
renderInput={(params) => (
<TextField
{...params}
error={weatherData?.error ? true : false}
fullWidth
label="name your city here..."
value={search}
onChange={(e) => {
setSearch(e.target.value);
}}
ref={inputField}
onKeyDown={(e) => e.key === "Enter" && handleSubmit(e)}
/>
)}
/>
);
}
I use material UI autocomplete to create a single-select dropdown.
But the problem is that when I click the close button placed right-side of the input, the onChange event didn't call and my state didn't update.
While in the multi-select mode this event successfully occurred.
Someone helps me to use the remove event in single-select mode.
This is my single select:
<Autocomplete<Option<T>>
onChange={(e: any, newValue) => {
if (newValue) {
handleChangeValue(newValue.value);
}
}}
sx={{ ...sx }}
id={id}
options={options}
isOptionEqualToValue={(newValue, option) =>
newValue.value === option.value
}
defaultValue={
defaultValue && {
value: defaultValue,
label: options.find((option) => option.value === defaultValue)?.label,
}
}
value={
value && {
value: value,
label: options.find((option) => option.value === value)?.label,
}
}
getOptionLabel={(option) => option.label || `${option.value}`}
renderOption={(props, option, { selected }) => (
<li value={option.value} {...props}>
<Checkbox
style={{ marginRight: 8 }}
checked={selected}
id={`${option.value}`}
/>
{option.label || `${option.value}`}
</li>
)}
renderInput={(params) => (
<TextField
value={value}
{...params}
placeholder={global.translate(placeholder)}
/>
)}
/>
this one is my multi-select autocomplete:
<Autocomplete
onChange={(e: any, value) => {
onChange(value);
}}
value={value}
sx={{ ...sx }}
multiple
id={id}
options={options}
disableCloseOnSelect
defaultValue={[...defaultValues]}
getOptionLabel={(option) => option.label}
isOptionEqualToValue={(newValue, option) =>
newValue.value === option.value
}
renderOption={(props, option, { selected }) => (
<li value={option.value} {...props}>
<Checkbox
icon={<CheckBoxOutlineBlankIcon fontSize="small" />}
checkedIcon={<CheckBoxIcon fontSize="small" />}
style={{ marginRight: 8 }}
checked={selected}
id={option.value}
/>
{option.label}
</li>
)}
renderInput={(params) => (
<TextField {...params} placeholder={placeholder} />
)}
/>
In your single-select mode Autocomplete component, you send handleChangeValue if only newValue exists.
So, in your single-select mode, you need to change this code:
<Autocomplete<Option<T>>
onChange={(e: any, newValue) => {
if (newValue) {
handleChangeValue(newValue.value);
}
}}
to this code:
<Autocomplete<Option<T>>
onChange={(e: any, newValue) => {
const valueToBeSent = newValue ? newValue.value : undefined;
handleChangeValue(valueToBeSent);
}}
in order to send onChange event on every value change.
I am building a category adder and previously I was only allowing the "add category chip" to show for the nooptions render, but I realized that if there was a category "software ngineer" and someone wanted to add "Software" you couldn't do it.
Ultimately I want to add the Add chip (which is different then the normal chips) to the end of all of the options with the search term in it. I tried adding it to the render option, but then it showed up after every option and I tried adding it to filter options but then I can't customize that chip.
Any suggestions on solving this?
My code:
<Autocomplete
id="Categories"
// set it to the left of the cell
style={{ width: '100%', marginTop: '1rem' }}
key={autocompleteKey}
options={
user.categories.length > 0
? user.categories.filter((c) => {
return !category.includes(c || c.charAt(0).toUpperCase() + c.slice(1));
})
: []
}
onChange={(event, value) => (handleAddCategoryToCompany(value))}
onInputChange={(event, value) => setNewCategory(value)}
popupIcon=""
filterOptions={(options) => {
console.log(options);
const result = [...options];
if (search.length > 0) result.push(search);
return result;
}}
renderOption={(event, value: string) => (
<>
<Chip
variant="outlined"
sx={{
m: '2px',
}}
onClick={() => handleAddCategoryToCompany(value)}
key={Math.random()}
label={value.charAt(0).toUpperCase() + value.slice(1)}
onDelete={() => removeFromGlobal(value)}
/>
{/* {search.length > 0
? (
<Chip
variant="outlined"
onClick={handleAddCategory}
key={Math.random()}
sx={{
m: '2px',
}}
label={search}
icon={<AddCircleIcon />}
/>
) : null} */}
</>
)}
renderInput={(par) => (
// Textfield where the options have a delete icon
<TextField
{...par}
fullWidth
label="Add Tag(s)"
margin="normal"
size="small"
name="Name"
onChange={(event) => (setSearch(event.target.value))}
key={autocompleteKey}
type="company"
value={search}
variant="outlined"
/>
)}
noOptionsText={search.length > 0
? (
<Chip
variant="outlined"
onClick={handleAddCategory}
key={Math.random()}
sx={{
m: '2px',
}}
label={search}
icon={<AddCircleIcon />}
/>
) : null}
/>
I figured it out by adding a modifier to the search option in the filter options and then had a conditional statement in render to look for this option. Seems to be working.
<Autocomplete
id="Categories"
// set it to the left of the cell
style={{ width: '100%', marginTop: '1rem' }}
key={autocompleteKey}
options={
user.categories.length > 0
? user.categories.filter((c) => {
return !category.includes(c || c.charAt(0).toUpperCase() + c.slice(1));
})
: []
}
onChange={(event, value) => (handleAddCategoryToCompany(value))}
onInputChange={(event, value) => setNewCategory(value)}
popupIcon=""
filterOptions={(options) => {
console.log(options);
const result = [...options];
if (search.length > 0) result.push(`${search} (new)`);
return result;
}}
renderOption={(event, value: string) => (
<>
{value.indexOf(' (new)') > -1
? (
<Chip
variant="outlined"
onClick={handleAddCategory}
key={Math.random()}
sx={{
m: '2px',
}}
label={search}
icon={<AddCircleIcon />}
/>
)
: (
<Chip
variant="outlined"
sx={{
m: '2px',
}}
onClick={() => handleAddCategoryToCompany(value)}
key={Math.random()}
label={value.charAt(0).toUpperCase() + value.slice(1)}
onDelete={() => removeFromGlobal(value)}
/>
)}
</>
)}
renderInput={(par) => (
// Textfield where the options have a delete icon
<TextField
{...par}
fullWidth
label="Add Tag(s)"
margin="normal"
size="small"
name="Name"
onChange={(event) => (setSearch(event.target.value))}
key={autocompleteKey}
type="company"
value={search}
variant="outlined"
/>
)}
noOptionsText={search.length > 0
? (
<Chip
variant="outlined"
onClick={handleAddCategory}
key={Math.random()}
sx={{
m: '2px',
}}
label={search}
icon={<AddCircleIcon />}
/>
) : null}
/>
I wish I could do such a thing using Autocomplete of material ui: wertarbyte
That is, inserting text (string) without having a list of elements from which you must select.
Therefore the noOptions message should not appear, every time the enter key is pressed on the keyboard the text is inserted.
Link: codesandbox
Code:
import React from "react";
import Chip from "#material-ui/core/Chip";
import Autocomplete from "#material-ui/lab/Autocomplete";
import { makeStyles } from "#material-ui/core/styles";
import TextField from "#material-ui/core/TextField";
const useStyles = makeStyles(theme => ({
root: {
width: 500,
"& > * + *": {
marginTop: theme.spacing(3)
}
}
}));
export default function Tags() {
const classes = useStyles();
return (
<div className={classes.root}>
<Autocomplete
multiple
id="tags-outlined"
options={[]}
defaultValue={["foo", "bar"]}
//getOptionLabel={(option) => option}
//defaultValue={[top100Films[13]]}
//filterSelectedOptions
renderInput={params => (
<TextField
{...params}
variant="outlined"
label="filterSelectedOptions"
placeholder="Favorites"
/>
)}
/>
</div>
);
}
In case you have simple elements (not objects, just strings), and you don't really need to handle state (your autocomplete is not controlled) you can use the freeSolo prop of the Autocomplete.
<Autocomplete
multiple
freeSolo
id="tags-outlined"
options={["foo", "bar"]}
defaultValue={["foo", "bar"]}
renderInput={params => (
<TextField
{...params}
variant="outlined"
label="filterSelectedOptions"
placeholder="Favorites"
/>
)}
/>
In case your elements are more complex and you do need to control the element:
Make sure the Autocomplete tag is a controlled one (you manage to value).
Listen to key down event on the TextField.
If the code is Enter (e.code === 'Enter') - take the value of the input and push it to the list of the current values that you have.
Make sure you also handle the onChange to handle the removal of elements:
Here is the code:
const [autoCompleteValue, setAutoCompleteValue] = useState(["foo", "bar"]);
return (
<Autocomplete
multiple
id="tags-outlined"
options={[]}
value={autoCompleteValue}
onChange={(e, newval, reason) => {
setAutoCompleteValue(newval);
}}
renderInput={params => (
<TextField
{...params}
variant="outlined"
label="filterSelectedOptions"
placeholder="Favorites"
onKeyDown={e => {
if (e.code === 'enter' && e.target.value) {
setAutoCompleteValue(autoCompleteValue.concat(e.target.value));
}
}}
/>
)}
/>
);
Check the live working example of both options: https://codesandbox.io/s/mui-autocomplete-create-options-on-enter-gw1jc
For anyone who wants to input the current best match on enter key press (as opposed to any custom text) you can use the autoHighlight prop.
<Autocomplete
multiple
autoHighlight
id="tags-outlined"
options={["foo", "bar"]}
defaultValue={["foo", "bar"]}
renderInput={params => (
<TextField
{...params}
variant="outlined"
label="filterSelectedOptions"
placeholder="Favorites"
/>
)}
/>
To do this, don't use the Autocomplete element from MUI. Just use a a standard TextField with the use of InputProps. All you need to do is add a onKeyDown listener to the TextField that listens for 'Enter' and when the function is triggered, have it add to an array of Chips in the InputProps. It might look something like this:
const [inputValue, setInputValue] = useState('');
const [chips, setChips] = useState([])
const inputChange = ({target: {value}}) => {setInputValue(value)};
const handleKeyDown = ({key}) => {
if(key === 'Enter') {
setChips([...chips, inputValue])
}
};
<TextField
fullWidth
variant="outlined"
label="Fish and Chips"
value={inputValue}
onChange={inputChange}
multiline
InputProps={{
startAdornment: chips.map((item) => (
<Chip
key={item}
label={item}
/>
)),
}}
/>
This is untested as written here, but it should work. I've done something similar in one of my apps.
I am referring to the documentation of React Material-UI (https://material-ui.com/components/autocomplete/).
In the demo code,
<Autocomplete
options={top100Films}
getOptionLabel={(option: FilmOptionType) => option.title}
style={{ width: 300 }}
renderInput={params => (
<TextField {...params} label="Combo box" variant="outlined" fullWidth />
)}
/>
I get how it works, but I am not sure how I am supposed to get the selected value.
For example, I want to use the onChange prop to this so that I can make some actions based on the selection.
I tried adding onChange={v => console.log(v)}
but the v does not show anything related to the selected value.
Solved by using passing in the (event, value) to the onChange props.
<Autocomplete
onChange={(event, value) => console.log(value)} // prints the selected value
renderInput={params => (
<TextField {...params} label="Label" variant="outlined" fullWidth />
)}
/>
The onChange prop works for multiple autocomplete values as well (#Steve Angello #ShwetaJ). The value returned is a list of all the selected options.
const [selectedOptions, setSelectedOptions] = useState([]);
const handleChange = (event, value) => setSelectedOptions(value);
const handleSubmit = () => console.log(selectedOptions);
.
.
.
<Autocomplete
multiple
autoHighlight
id="tags-outlined"
options={top100Films}
getOptionLabel={(option) => option.title}
onChange={handleChange}
filterSelectedOptions
renderInput={(params) => (
<TextField
{...params}
variant="standard"
/>
)}
/>
.
.
.
<button onClick={handleSubmit}>Submit!</button>
You can use useState to store the recevied value and onChange to get the value:
const [selected, setSelected] = useState([]);
return (
<Autocomplete
onChange={(event, value) => setSelected(value)}
renderInput={(params) => <TextField {...params} label="selected" />}
/>
);
Here is TS working example
const tags = ["perimeter", "Algebra", "equation", "square root"];
const handleInput = (e: React.SyntheticEvent, value: string[]) => {
console.log(value);
};
<Autocomplete
multiple
options={tags}
onChange={handleInput}
renderTags={(value: readonly string[], getTagProps) =>
value.map((option: string, index: number) => (
<Chip
variant="outlined"
label={option}
{...getTagProps({ index })}
/>
))
}
renderInput={(params) => (
<TextField
{...params}
variant="filled"
label="Tags"
placeholder="select question tags"
/>
)}
/>
============ Output ===============