I am working with material ui autocomplete.
<Autocomplete
multiple
id="tags-outlined"
options={options}
getOptionLabel={(option) => option && option.name}
value={catArray}
onChange={handleCategoryFilter}
filterSelectedOptions
renderInput={(params) => (
<TextField
{...params}
variant="outlined"
placeholder="Categories"
/>
)}
/>
Firstly I want selected value not to show in options secondly I want to clear autocomplete. Can you please guide me how can I do these things.
I am clearing the values by setCatArray([]) but it is not workinh
You can use material ui autocomplete's default prop filterSelectedOptions. If true, it will hide the selected options from the list box.
For clearing the values of autocomplete, it gives default clear icon at the end of the select box. you can clear it from there.
Try my sandbox link. Also try some more material ui demos here.
UPDATE: If you want to manage clearing values you can use value prop of autocomplete and manage it in onchange by updating it's value.
<Autocomplete
multiple
id="tags-outlined"
options={top100Films}
value={values}
getOptionSelected={(option, value) => value.title === option.title}
getOptionLabel={(option) => option.title}
filterSelectedOptions
onChange={(e, valueTags) => {
e.preventDefault();
const valuesArray = [];
valueTags.forEach((valueTag) => {
valuesArray.push({
title: top100Films
.filter((tag) => valueTag.title === tag.title)
.shift().title
});
});
setValues(valuesArray);
}}
renderInput={(params) => (
<TextField
{...params}
variant="outlined"
label="filterSelectedOptions"
placeholder="Favorites"
/>
)}
/>
Have you tried adding autocomplete=false to the list of properties in the component?
If you want to filter out selected options from autocomplete. Pass filterSelectedOptions={true} to your component
Secondly, you can clear the value by taking control of the selected values and setting it to an empty array. Here is my complete example
const options = ["one", "two", "three", "four"];
export default function MyAutocomplete() {
const [values, setValues] = React.useState<string[]>([]);
const onChange = (_, value) => {
setValues(value);
};
const clearSelected = () => {
setValues([]);
};
return (
<>
<button onClick={clearSelected}>Clear selected</button>
<Autocomplete
multiple
id="tags-outlined"
options={options}
getOptionLabel={(option) => option}
value={values}
onChange={onChange}
filterSelectedOptions
renderInput={(params) => (
<TextField {...params} variant="outlined" placeholder="Categories" />
)}
/>
</>
);
}
Live Example
const options = ["one", "two", "three", "four"];
export default function MyAutocomplete() {
const [values, setValues] = React.useState([]);
const onChange = (_, value) => {
setValues(value);
};
const clearSelected = () => {
setValues([]);
};
return (
<>
<button onClick={clearSelected}>Clear selected</button>
<Autocomplete
multiple
id="tags-outlined"
options={options}
getOptionLabel={(option) => option}
value={values}
onChange={onChange}
filterSelectedOptions
renderInput={(params) => (
<TextField {...params} variant="outlined" placeholder="Categories" />
)}
/>
</>
);
}
Related
On MUI Autocomplete component where the attribute is multiple, then the value prop returns 0 or undefined when we choose anyone of the selected option.
<Autocomplete
value={v.education}
onChange={handleEducationChange}
className={classes.textOutline}
multiple
id="virtualize-demo"
name="education"
style={{ width: 600 }}
disableCloseOnSelect
ListboxComponent={ListboxComponent}
options={educationList()}
getOptionLabel={(option) => option.title}
isOptionEqualToValue={(option, value) =>
option.title === value.title
}
renderOption={(props, option, { selected }) => (
<li {...props}>
<Checkbox
icon={icon}
checkedIcon={checkedIcon}
style={{ marginRight: 8 }}
checked={selected}
/>
{option.title}
</li>
)}
renderInput={(params) => (
<TextField
{...params}
variant="outlined"
name="education"
placeholder="Select your Qualification"
label="Education"
fullWidth
/>
)}
/>
// handleEducationChange
const initialState = { education: "", occupation: "" };
const [selectedOption, setSelectedOption] = useState([], initialState);
const handleEducationChange = (event) => {
const { name, values } = event.target;
setSelectedOption({ ...selectedOption, [name]: values });
console.log(values);
};
I need the selected value to be passed with value prop and that can be validated and posted to backend... kindly update the solution for this, Thanks.
My options looks like this
const options = [
{
"VaccinationType": "Sample"
},
{
"VaccinationType": "Another Sample"
}
]
Code:
const [vacType, setVacType] = useState('');
<Autocomplete
value={vacType}
onChange={(e, value) => {
console.log(value);
setVacType(value);
}}
options={options}
getOptionLabel={(option) => option.VaccinationType}
isOptionEqualToValue={(option, value) => option.VaccinationType === value.VaccinationType}
renderInput={(params) => (
<TextField
{...params}
variant="outlined"
size="small"
/>
)}
/>
I tried logging my value it still outputs the object { VaccinationType: "Sample" }. I want it to only output "Sample"
In MUI 4 I'm using this getOptionSelected={(option, value) => option?.VaccinationType === value?.VaccinationType}
Autocomplete options care about the item of the array which you put. According to your code, each item has all object values.
I searched to find a way but I couldn't.
There is a way probably you already thought;
You can edit options parameter like options={options.map(o => o.VaccinationType)} and remove VaccinationType key on getOptionLabel and isOptionEqualToValue
<Autocomplete
value={vacType}
onChange={(e, value) => {
console.log(value);
setVacType(value);
}}
options={options.map(o => o.VaccinationType)}
getOptionLabel={(option) => option}
isOptionEqualToValue={(option, value) =>
option === value
}
renderInput={(params) => (
<TextField {...params} variant="outlined" size="small" />
)}
/>
So I think u forgot to use onInputChange and InputValue properties for MUI Autocomplete, according to https://mui.com/material-ui/react-autocomplete/ these properties are needed in this case here u can read more https://mui.com/material-ui/api/autocomplete/ so please check this solution which works for me:
const [vacType, setVacType] = useState<any>('Sample')
const [inputValue, setInputValue] = useState('Sample')
const options: any[] = [
{
VaccinationType: 'Sample'
},
{
VaccinationType: 'Another Sample'
}
]
<Autocomplete
value={vacType} //here u set default Value and change whenever it changes a list choice
inputValue={inputValue} //here u set default Input and change whenever it changes by typing
onChange={(event: any, newValue: any | null) => {
setVacType(newValue)
}}
onInputChange={(event, newInputValue) => {
setInputValue(newInputValue)
}} // handles typing
options={options}
getOptionLabel={(option: { VaccinationType: string }) => {
return option?.VaccinationType
}}
isOptionEqualToValue={(option, value) =>
option?.VaccinationType === value?.VaccinationType
}
renderInput={params => (
<TextField {...params} variant="outlined" size="small" />
)}
/>
Hope it helps!
Also to answer your problem with console.log
your code:
onChange={(e, value) => {
console.log(value);
setVacType(value);
}}
exchanged to :
onChange={(event: any, newValue: any | null) => {
console.log('newValue')
console.log(newValue)
setVacType(newValue)
}}
gives object but you on this Autocomplete provide objects then seting values is in objects so u just need to add console.log(newValue.VaccinationType) but not for setVacType(newValue) and Autocomplete will remember last choice
I don't know why you want to do that!,
You can simply use value object wherever you want, and use any key of the object, take the value object as it's then use value.VaccinationType.
But, if you want to do this:
<Autocomplete
{...props}
value={options.find(op => op.VaccinationType === vacType)}
onChange={(e, value) => {
console.log(value); //Result: { "VaccinationType": "Sample" }
setVacType(value.VaccinationType); // <==== Here, add `.VaccinationType`
}}
/>
I am using Material UI v4.
I have a component which takes all the users and show them in dropdown but I am not able to select default value. I tried following sandbox but it did not worked for me: [https://codesandbox.io/s/material-demo-4mhcj?file=/demo.js][CodeSandBox]
For ex- test#gmail.com
react-hook-form : ^7.20.5
I tried giving a default value to both Controller and Autocomplete but it does not work for the first time.
Any idea what I am doing wrong here?
// data is something like
// [{name: 'ABCDE', email: 'ABCDEEE#gmail.com'}, {name: 'eeeeee', email: 'eeeeee12#gmail.com'}]
const UserSelection = ({ data = [], onChangeHandler }) => {
const { control } = useForm({});
const selectedUserEmail = "ABCDEEE#gmail.com";
return (
<>
<Controller
name="combo-box-demo"
control={control}
defaultValue={data.find(item => item.email === selectedUserEmail)}
render={() =>
<Autocomplete
id="combo-box-demo"
size="small"
options={data}
defaultValue={data.find(item => item.email === selectedUserEmail)}
onChange={onChangeHandler}
getOptionLabel={option => option.name }
renderOption={option => option.name}
renderInput={(params) => (
<TextField
{...params}
variant="outlined"
placeholder="Select"
/>
)}
/>
}
/>
</>
);
};
export default UserSelection;
I found the answer, so I am posting here:
The problem was data which was coming is asynchronous and autocomplete was not able to render it properly.
For now I am using:
const UserSelection = ({ data = [], onChangeHandler }) => {
const selectedUser = {name: 'ABCDE', email: 'ABCDEEE#gmail.com'};
return (
<Autocomplete
id="combo-box-demo"
options={data}
defaultValue={selectedUser}
onInputChange={onChangeHandler}
getOptionLabel={option => option.name }
renderOption={option => option.name}
renderInput={(params) => (
<TextField
{...params}
variant="outlined"
placeholder="Select"
/>
)}
/>
);
};
export default UserSelection;
And where ever I am using above component, I use like
data ? <UserSelection/> : null
Also instead of using onChange I used onInputChange which helps in getting default value
then it works and loads default user, hope it helps to community
import React, { useEffect, useRef } from "react";
import TextField from "#material-ui/core/TextField";
import Autocomplete from "#material-ui/lab/Autocomplete";
export default function FreeSolo(props) {
const [vendors, setVendors] = React.useState([]);
const [value, setValue] = React.useState();
const nameRef = useRef();
useEffect(() => {
sendDataToParent();
}, [value]);
const sendDataToParent = async () => {
await props.parentFunction(value);
};
return (
<div style={{}}>
<Autocomplete
freeSolo
id="free-solo-2-demo"
options={props.vendorData.map((option) => option.name)}
renderInput={(params) => (
<TextField
{...params}
value={value}
required
inputRef={nameRef}
onChange={(e) => {
setValue(e.target.value);
sendDataToParent();
}}
label="Vendor Name"
margin="normal"
variant="standard"
InputProps={{ ...params.InputProps, type: "search" }}
/>
)}
/>
</div>
);
}
I tried to do it using renderOption but could not get it working. I need to have the options to be clickable links so that whenever user selects of the options, he is redirected to the link.
EDIT: Solved using renderOption
renderOption={(option) => (
<React.Fragment>
<span
style={{ cursor: "pointer" }}
onClick={() => {
window.location.href = `/allvendors/${option.id}`;
}}
>
{option.name} - Click to visit the Vendor
</span>
</React.Fragment>
)}
Instead of making the options clickable links, you can redirect to the link using the onChange prop of the Autocomplete component.
I'm assuming each option in your vendorData has a name and also a link e.g.
{
name: "Google",
link: "https://www.google.com"
}
To be able to access the link from this object in the Autocomplete component's onChange, you'll need to change the options map function to return the whole option. After this change, if you try to click to open the dropdown, it will throw an error because the option label needs to be a string (e.g. the option name) and not an object (e.g. option). So, we need to add the getOptionLabel prop and return the option.name.
Finally, in the onChange function, we set the window.location.href equal to the option.link, which changes the current page's URL to the link and directs the user to that link.
<div style={{}}>
<Autocomplete
freeSolo
id="free-solo-2-demo"
getOptionLabel={(option) => option.name}
options={props.vendorData.map((option) => option)}
onChange={(event: any, option: any) => {
window.location.href = option.link;
}}
renderInput={(params) => (
<TextField
{...params}
value={value}
required
inputRef={nameRef}
onChange={(e) => {
setValue(e.target.value);
sendDataToParent();
}}
label="Vendor Name"
margin="normal"
variant="standard"
InputProps={{ ...params.InputProps, type: "search" }}
/>
)}
/>
</div>
In the hooks version of material UI I can't seem to be able to clear the autocomplete after an onChange event:
// #flow
import React, { useRef, useState } from "react";
import "./Autocomplete.scss";
import AutocompleteUI from "#material-ui/lab/Autocomplete";
import TextField from "#material-ui/core/TextField";
function Autocomplete(props) {
const { options } = props;
const [value, setValue] = useState();
const container = useRef();
const input = useRef();
function onChange(event, newValue) {
if (!newValue) return;
props.onChange(newValue);
setValue(undefined);
input.current.value = "";
event.target.value = "";
}
function renderInput(params) {
return (
<TextField
inputRef={input}
{...params}
inputProps={{
...params.inputProps,
autoComplete: "disabled", // disable autocomplete and autofill
}}
margin="none"
fullWidth
/>
);
}
return (
<div className="Autocomplete-container">
{value}
<AutocompleteUI
ref={container}
options={options}
autoHightlight={true}
clearOnEscape={true}
autoSelect={true}
// freeSolo={true}
getOptionLabel={option => option.title}
renderInput={renderInput}
value={value}
onChange={onChange}
/>
</div>
);
}
export default Autocomplete;
Diving into the source code I've noticed the component uses useAutocomplete hook internally. However, neither setInputValue nor resetInputValue which live internally inside that hook are exposed outside. Is there a way to accomplish an input clear after an onChange?
You need to set the inputValue prop to your valueState and on onhange function just clear the valueState
<Autocomplete
inputValue={valueState}
onChange={(value, option) =>
{
setOptions([])
setValueState("")
}}
renderInput={params => (
<TextField
dir="rtl"
onChange={(event) =>
{
setValueState(event.target.value)
}}
{...params}
label="Search Patient"
variant="filled"
InputProps={{
...params.InputProps,
endAdornment: (
<React.Fragment>
{loading ? (
<CircularProgress color="inherit" size={20} />
) : null}
{params.InputProps.endAdornment}
</React.Fragment>
)
}}
/>
)}
/>
I had the same issue and I solved it with this :
const [search, setSearch] = useState("");
...
<Autocomplete
id="grouped-demo"
options={tagsList}
getOptionLabel={(option) => option.tag}
onChange={(event, value) =>value ? setSearch(value.tag) : setSearch(event.target.value)}
style={{width: 700}}
renderInput={(params) => <TextField {...params} label="Search" variant="outlined"/>}
/>
I encountered a similar scenario using Autocomplete/Textfield in a Search/Nav bar. The value would always be left behind after using a history.push or other Router function in the onChange event. The trick is to set the inputValue = "" . Every time the component renders, the previous value will be removed. See below
<Autocomplete
{...defaultProps}
onChange={(event, value) => {
if(value)
router.history.push(`/summary`);
}}
filterOptions={filterOptions}
clearOnEscape={true}
inputValue=""
renderInput={params => <TextField {...params}
label="Quick Search" fullWidth
InputProps={{...params.InputProps,
'aria-label': 'description',
disableUnderline: true,
}}/>}
/>
yo! I'm pretty sure the Textfield component from material takes an "autoComplete" prop, and you can pass that the string "false". Also, it does not go in inputProps, try that out.
<Textfield autoComplete="false" />
I had the same issue and I solved it with this :
const [value, setValue] = useState(null);
Then you don't need to use refs.