Reputation: 1075
In my React app I have an input which could take value from the dropdown list. For that putpose I use material-ui Autocomplete and TextField components.
Question: how can I programmaticaly set an input value by clicking on the button without choosing from the dropdown list? For example, I want to set "The Godfather" from the example and this value should be visually seen in the input.
import React from "react";
import Autocomplete from "@material-ui/lab/Autocomplete";
import { TextField, Button } from "@material-ui/core";
export default function ComboBox() {
const handleClick = () => {
// set value in TextField from dropdown list
};
return (
<React.Fragment>
<Autocomplete
options={top100Films}
getOptionLabel={option => option.title}
style={{ width: 300 }}
renderInput={params => (
<TextField
{...params}
label="Combo box"
variant="outlined"
fullWidth
/>
)}
/>
<Button onClick={handleClick}>Set value</Button>
</React.Fragment>
);
}
// Top 100 films as rated by IMDb users. http://www.imdb.com/chart/top
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 }
];
Upvotes: 32
Views: 67813
Reputation: 1
when the option is not present in the dropdown it will add a new option
import * as React from 'react';
import TextField from '@mui/material/TextField';
import Autocomplete, { createFilterOptions } from '@mui/material/Autocomplete';
const filter = createFilterOptions();
export default function FreeSoloCreateOption() {
const [value, setValue] = React.useState(null);
return (
<Autocomplete
value={value}
onChange={(event, newValue) => {
if (typeof newValue === 'string') {
setValue({
title: newValue,
});
} else if (newValue && newValue.inputValue) {
// Create a new value from the user input
top100Films.push({title: newValue.inputValue})
setValue({
title: newValue.inputValue,
});
} else {
setValue(newValue);
}
}}
filterOptions={(options, params) => {
const filtered = filter(options, params);
const { inputValue } = params;
// Suggest the creation of a new value
const isExisting = options.some((option) => inputValue === option.title);
if (inputValue !== '' && !isExisting) {
filtered.push({
inputValue,
title: `Add "${inputValue}"`,
});
}
return filtered;
}}
selectOnFocus
clearOnBlur
handleHomeEndKeys
id="free-solo-with-text-demo"
options={top100Films}
getOptionLabel={(option) => {
// Value selected with enter, right from the input
if (typeof option === 'string') {
return option;
}
// Add "xxx" option created dynamically
if (option.inputValue) {
return option.inputValue;
}
// Regular option
return option.title;
}}
renderOption={(props, option) => <li {...props}>{option.title}</li>}
sx={{ width: 300 }}
freeSolo
renderInput={(params) => (
<TextField {...params} label="Free solo with text demo" />
)}
/>
);
}
// Top 100 films as rated by IMDb users. http://www.imdb.com/chart/top
const top100Films = [
{ title: 'The Shawshank Redemption', year: 1994 },
{ title: 'The Godfather', year: 1972 },
{ title: 'The Godfather: Part II', year: 1974 }
];
Upvotes: 0
Reputation: 341
No one gives the correct answer...
const options = [
{ label: "A", value: 1 },
{ label: "B", value: 2 },
{ label: "A", value: 3 },
];
function MyInput() {
const [value, setValue] = useState(options[0].value);
return (
<Autocomplete
value={options.find((option) => option.value === value)}
onChange={(_, v) => setValue(v?.value)}
options={options}
getOptionLabel={(option) => option.label}
renderInput={(params) => (
<TextField {...params}/>
)}
/>
)
}
Upvotes: 4
Reputation: 486
if you want to show the default selected value in input you must also set inputValue property and onInputChange event of the Autocompelete component
changes in state:
const [value, setValue] = useState("");
const [inputValue, setInputValue] = useState("");
changes in handle click
const handleClick = () => {
setValue(top100Films[0]);
setInputValue(top100Films[0]);
};
changes in autocompelete
<Autocomplete
{...custom}
value={value}
inputValue={inputValue}
onChange={(event, newValue) => {
setValue(newValue);
}}
onInputChange={(event, newInputValue) => {
setInputValue(newInputValue);
}}
options={top100Films}
getOptionLabel={option => option.title}
renderInput={(params) => (
<TextField
{...input}
{...params}
variant="outlined"
/>
)}
/>
Upvotes: 8
Reputation: 1237
If you're here trying to test a change handler that is called from MUI's Autocomplete
component:
In your setupTests.js file
import '@testing-library/jest-dom/extend-expect'
document.createRange = () => ({
setStart: () => {},
setEnd: () => {},
commonAncestorContainer: {
nodeName: 'BODY',
ownerDocument: document
}
})
In your test file:
import { render, fireEvent } from '@testing-library/react'
...
const { getByRole } = render(<MyComponentWithAutocomplete />)
const autocomplete = getByRole('textbox')
// click into the component
autocomplete.focus()
// type "a"
fireEvent.change(document.activeElement, { target: { value: 'a' } })
// arrow down to first option
fireEvent.keyDown(document.activeElement, { key: 'ArrowDown' })
// select element
fireEvent.keyDown(document.activeElement, { key: 'Enter' })
expect(autocomplete.value).toEqual('Arkansas')
expect(someChangeHandler).toHaveBeenCalledTimes(1)
For more examples, check out the tests in the library
Upvotes: 1
Reputation: 2900
you can store desired value in state and pass it to auto complete component.
Import useState:
import React, { useState } from 'react';
using useState:
const [val,setVal]=useState({})
changin value on click of button
const handleClick = () => {
setVal(top100Films[0]);//you pass any value from the array of top100Films
// set value in TextField from dropdown list
};
and pass this value to component in render
<Autocomplete
value={val}
options={top100Films}
getOptionLabel={option => option.title}
style={{ width: 300 }}
renderInput={params => (
<TextField
{...params}
label="Combo box"
variant="outlined"
fullWidth
/>
)}
/>
Upvotes: 24