Material UI Autocomplete: highlighted option should become input value - javascript

When a user browses through the options using the arrow keys on his keyboard, I take the value from the highlighted option and use it as the current input value (input here has its own state).
Unfortunately, the highlighted state of the option is lost upon saving the title or value of the option as the input. Is there a way to not lose it?
Here is an example:
https://codesandbox.io/s/modern-rgb-5tew1p?file=/demo.tsx
P.S.:
Although this property sounded like it was made for it, includeInputInList does not help.
Thanks in advance!

Try this (I made some changes to your code like adding reason and isOptionEqualToValue):
export default function ComboBox() {
const [input, setInput] = React.useState(null);
const handleInputChange = (event, value) => {
setInput(value);
};
const handleHighlightChange = (event, option, reason) => {
if (option && reason === "keyboard") {
setInput(option);
}
};
const handleFilterOptions = (currentOptions) => currentOptions;
return (
<Autocomplete
id="combo-box-demo"
value={input}
onChange={handleInputChange}
options={top100Films}
isOptionEqualToValue={(option, value) => option.label === value.label}
includeInputInList={true}
onHighlightChange={handleHighlightChange}
getOptionLabel={(option) => option.label}
filterOptions={handleFilterOptions}
style={{ width: 300 }}
renderInput={(params) => (
<TextField {...params} label="Combo box" variant="outlined" />
)}
/>
);
}

Related

How to get the dynamic image inside 'startAdornment' in MUI's Autocomplete?

I am using MUI's autocomplete component to display some of my objects as suggestions.
Everything is working fine, but I am placing an avatar as a start adornment inside of the textfield (inside of renderInput), where I wish to put the value of corresponding image prop of what is selected.
What I want : I want that whatever value is selected in autocomplete, (there is an image property inside my object, whose array i mapped to options prop of autocomplete). So, I want that corresponding image, together with the option label (inside of textfield), the corresponding image should also be shown inside startAdornment.
Well, I want it similar to LinkedIn's company field which we fills while posting a new job.
Here's my MUI Autocomplete, I am new to 'typescript'.
<Autocomplete
open = {open}
onOpen = {() => setOpen(true)}
onClose = {() => setClose(true)}
options = {items.sort((a, b) => -b.name.localeCompare(a.name))}
isOptionEqualToValue = {(option, value) => option.name === value.name}
getOptionLabel = {(option : any) => option.name}
renderInput = {(params : any ) => (
<TextField
{...params}
className = {'inputField'}
placeholder = {'Enter item name'}
label = {'items'}
InputProps = {{
...params.InputProps,
startAdornment : ( <Avatar src = {params.image} /> )
}} />
)}
renderOption = {(props, option) => {
return (
<li
key = {option.id}
{option.name}
</li> )}} />
so I want that whatever name is selected from autocomplete, its corrosponding image should be displayed into the Avatar(inside of startadornment).
How to achieve this?
And, yes, here is my Object array be like -
[{ id : number, name : string, image : string }, {...}, {...}, and so on...];
image here is url of the image, ( that I wish to show into the avatar inside startAdornment.)
Do i need to provide a new state for this?
All suggestions would be appretiated, eagerly looking for answers that fits.
My approach would be to create a state to store the select value and whenever this state changes it would update the avatar component:
const [value, setValue] = useState("");
const AvatarAdornment = useMemo(()=>
<Avatar src={items.find(item =>item.name === value).image} />,
[value, items])
And in your autocomplete component use it like:
<Autocomplete
open = {open}
onOpen = {() => setOpen(true)}
onClose = {() => setClose(true)}
options = {items.sort((a, b) => -b.name.localeCompare(a.name))}
isOptionEqualToValue = {(option, value) => option.name === value.name}
getOptionLabel = {(option : any) => option.name}
renderInput = {(params : any ) => (
<TextField
{...params}
className = {'inputField'}
placeholder = {'Enter item name'}
label = {'items'}
InputProps = {{
...params.InputProps,
startAdornment : ( <AvatarAdornment/> )
}} />
)}
renderOption = {(props, option) => {
return (
<li
key = {option.id}
{option.name}
</li> )}} />

Material UI Autocomplete: onChange is not triggered

In my example of Material UI's Autocomplete I want to select an option via keyboard events:
Browse through options with Up and Down arrow keys
Select desired option with ENTER
Unfortunately, the onChange is not triggered.
https://codesandbox.io/s/condescending-panna-xinkdw?file=/demo.tsx
Try using onClose, as when you navigate with your keyboard your state value is updated to whatever is highlighted, so if you wanna trigger an event when user press ENTER, just use onClose, and it gives you pretty much same props as onChange
This part in your causing onChange() not to trigger,
because of setInput(option):
const handleHighlightChange = (event, option, reason) => {
if (option && reason === "keyboard") {
setInput(option);
}
};
You can just call handleOnChange() withtout the using the prop onHighlightChange
for example:
export default function ComboBox() {
const [input, setInput] = React.useState(null);
const handleOnChange = (event, value, reason) => {
if (reason === "selectOption") {
window.location.href = value.url;
}
};
const handleFilterOptions = (currentOptions) => currentOptions;
return (
<Autocomplete
id="combo-box-demo"
value={input}
onChange={handleOnChange}
options={top100Films}
isOptionEqualToValue={(option, value) => option.label === value.label}
includeInputInList={true}
getOptionLabel={(option) => option.label}
filterOptions={handleFilterOptions}
style={{ width: 300 }}
renderInput={(params) => (
<TextField {...params} label="Combo box" variant="outlined" />
)}
/>
);
}

Updated state not reflecting properly

I have below code where I am checking or unchecking the checkbox based on some conditions, and I came across an issue where I am trying to check the checkbox, and it is failing the first time and from the second time onwards works perfectly.
export const AntdDefaultOverrideInputNumberAdapter = ({
input: { onChange, value },
disabled,
defaultValue,
formatter,
...rest
}) => {
const [isDefaultValueOverriden, setIsDefaultValueOverriden] = useState(
!!value && value !== defaultValue
);
const handleCheckboxChange = () => {
const hasOverride = !isDefaultValueOverriden;
setIsDefaultValueOverriden(hasOverride);
onChange(hasOverride && !!value ? value : defaultValue);
};
const handleOverrideChange = (v) => {
onChange(v);
};
return (
<Badge
offset={[0, -6]}
count={
<div>
<Checkbox
disabled={disabled}
checked={isDefaultValueOverriden}
onChange={handleCheckboxChange}
style={{ zIndex: 10 }}
/>
</div>
}
>
<InputNumber
size="small"
onChange={handleOverrideChange}
disabled={disabled || !isDefaultValueOverriden}
style={{ width: 65 }}
value={isDefaultValueOverriden ? value : defaultValue}
formatter={formatter}
{...rest}
/>
</Badge>
);
};
I am not sure where I am wrong with the above code, The problem only appears on trying to check the checkbox the first time, and it disappears from the second time onwards..
Could anyone suggest any idea on this? Many thanks in advance!!
I am using the "ANTD" library for the checkbox, and the "value" is an empty string, and the defaultValue is "5"

Input unfocus after typing something in it, i put an onChange function that sets a state using setstate(react hooks) (TextField material ui)

When using a setting a state((useState() / setState()), the input unfocuses, idk why?
pls help
React hook State
const [username, setUsername] = useState("");
this is the my own component which returns a textfield but with my own styles
function FormInput({ onChange, ...rest }) {
const classes = formInputStyles();
return (
<div>
<TextField
onChange={(e) => onChange(e.target.value)}
InputProps={{ classes, disableUnderline: true }}
{...rest}
/>
</div>
);
}
Like, i said in the title whenever i type something in the input field it unfocuses and clears the input field.
It dosen't unfocus when i use the normal < TextField > from material ui.
i tried making a whole new function for setting state but that didnt work
<FormInput
onChange={(value) => {
setUsername(value);
}}
label="Username"
variant="filled"
></FormInput>

React autocomplete component, call endpoint every time a letter is typed

I am working with react and the component autocomplete of material-ui, I need help with the following problem.
In the examples of autocomplete I saw you need to have all elements of the list in the frontend to use the autocomplete, in my case I get the list from a web service and it could be huge, so instead of searching for the whole list I want that every time a letter is typed in the autocomplete it generates a search to the web service filtering names according to the input that is being written and with a max results of 10 elements. The endpoint of the webservice already has a filter property where you can pass the quantity of results you want and the letters you want of the name.The only thing that the autocomplete has to do is everytime you type a letter it hits the endpoint (filtering with the word that is being typed) and updates the list of elements of the autocomplete.
Right now I have the following code, the problem is that it searches the whole list when you click the autocomplete but when you type each letter it doesn't do anything.
import Autocomplete from '#material-ui/lab/Autocomplete';
import TextField from '#material-ui/core/TextField';
import CircularProgress from '#material-ui/core/CircularProgress';
const [open, setOpen] = React.useState(false);
const [organizationList, setOrganizationList] = React.useState([]);
const loading = open && organizationList.length === 0;
React.useEffect(() => {
let active = true;
if (!loading) {
return undefined;
}
(async () => {
if (active) {
try {
setOrganizationList(await api.post('/v1/organizations/search', {maxResults:10}));
} catch (error) {
snackbar.showMessage(error, "error");
}
}
})();
return () => {
active = false;
};
}, [loading]);
React.useEffect(() => {
if (!open) {
setOrganizationList([]);
}
}, [open]);
The definition of the autocomplete:
<Autocomplete
id="asynchronous-demo"
style={{ width: 300 }}
open={open}
onOpen={() => {
setOpen(true);
}}
onClose={() => {
setOpen(false);
}}
getOptionSelected={(option, value) => option.orgName === value.orgName}
getOptionLabel={(option) => option.orgName}
options={organizationList}
loading={loading}
renderInput={(params) => (
<TextField
{...params}
label="Asynchronous"
variant="outlined"
InputProps={{
...params.InputProps,
endAdornment: (
<React.Fragment>
{loading ? <CircularProgress color="inherit" size={20} /> : null}
{params.InputProps.endAdornment}
</React.Fragment>
),
}}
/>
)}
/>
To hit the endpoint I have this:
setOrganizationList(await api.post('/v1/organizations/search', {maxResults:10}));
I need to pass the input of the autocomplete every time a letter is typed, like this:
setOrganizationList(await api.post('/v1/organizations/search', {name:inputAutocomplete,maxResults:10}));
Thanks a lot for the help.
Im new to react by the way.
In material-ui library Autocomplete component has a props onChange that can be used like this.
onChange={(event, newValue) => {
setValue(newValue);
}}
You should be interested in the second parameter newValue. Thus, you will receive a new input value every time a letter is typed.
Therefore, just move the logic for getting the list into this callback.
You can read more about controllable state in the material-ui documentation
Implementing the onChange function and giving it the function you already made should give you the solution you want.

Categories