Reputation: 143
I am trying to apply the principle of Add xyx
in MUI Autocomplete in Reactjs, using single dimension i.e [1,2,3,4,5]
, i.e. without objects, So far I have got the examples and references with objects only. Is there any way possible to achieve so, for reference I am trying to achieve this using only single array, and I want the Add <YOUR_SEARCH_TERM>
option, I have so far got only the input search term, I want to append Add
as a prefix but if I add that Add
, it also reflects in the input box as well.
Upvotes: 1
Views: 3831
Reputation: 768
There is a way you can achieve this. Please see the Code Sandbox example I created. I modified the Material UI example you had linked.
In this example, the options are numbers in an array, instead of objects i.e. [0, 1, 2, 3, 4, 5]
.
There are three steps:
Add
the user's input in the filtered options, we push the user's input with the Add
prefix.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);
if (inputValue !== "" && !isExisting) {
filtered.push(`Add ${inputValue}`);
}
return filtered;
}}
As you rightly pointed out, if you select this, the Add
prefix will also appear in the input box. For example, if we select Add 6
, the input box will show Add 6
. We only want to show 6
.
We can achieve this by adding a replace
in the getOptionLabel
function. This controls how the option is rendered. Here we are
replacing Add
from the option we selected with an empty string.
This removes the Add
prefix and the space between the prefix and
the input. For example, instead of Add 6
being displayed, only 6
will be displayed.
getOptionLabel={(option) => {
// Value selected with enter, right from the input
if (typeof option === "string") {
const updatedOption = option.replace("Add ", "");
return updatedOption;
}
// Add "xxx" option created dynamically
if (option.inputValue) {
return option.inputValue;
}
// Regular option
return option.toString();
}}
Add
prefix when we setValue
in our onChange
function. Similar to Step 2, we have to add a replace
in the onChange
function to remove the Add
prefix.onChange={(event, newValue) => {
if (typeof newValue === "string") {
const updatedValue = newValue.replace("Add ", "");
setValue(updatedValue);
} else if (newValue && newValue.inputValue) {
// Create a new value from the user input
setValue(newValue.inputValue);
} else {
setValue(newValue);
}
}}
Putting it altogether:
import * as React from "react";
import TextField from "@mui/material/TextField";
import Autocomplete, { createFilterOptions } from "@mui/material/Autocomplete";
import "./styles.css";
const numbers = [0, 1, 2, 3, 4, 5];
const filter = createFilterOptions();
export default function App() {
const [value, setValue] = React.useState(null);
return (
<div className="App">
<Autocomplete
value={value}
onChange={(event, newValue) => {
if (typeof newValue === "string") {
const updatedValue = newValue.replace("Add ", "");
setValue(updatedValue);
} else if (newValue && newValue.inputValue) {
// Create a new value from the user input
setValue(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);
if (inputValue !== "" && !isExisting) {
filtered.push(`Add ${inputValue}`);
}
return filtered;
}}
selectOnFocus
clearOnBlur
handleHomeEndKeys
id="free-solo-with-text-demo"
options={numbers}
getOptionLabel={(option) => {
// Value selected with enter, right from the input
if (typeof option === "string") {
const updatedOption = option.replace("Add ", "");
return updatedOption;
}
// Add "xxx" option created dynamically
if (option.inputValue) {
return option.inputValue;
}
// Regular option
return option.toString();
}}
renderOption={(props, option) => <li {...props}>{option}</li>}
sx={{ width: 300 }}
freeSolo
renderInput={(params) => (
<TextField {...params} label="Array of numbers demo" />
)}
/>
</div>
);
}
Upvotes: 4