In a React project, I have an Autocomplete component which has country name and its relevant calling codes displayed in drop-down list. When selected on list renders the desired data, but, when refreshed, data is null and doesn't show the default data.
const [newValue, setNewValue] = useState({});
const [textToggle, textToggleState] = useState(false);
render(
<div
style={{ cursor: "pointer" }}
onClick={() => {
textToggleState(!textToggle);
}}
>
<h5>+{newValue == null ? "91" : newValue.calling_code}</h5> {/* <-- Value gets null when refreshed */}
</div>
{textToggle ? (
<Autocomplete
id="size-small-standard"
size="small"
options={cities}
onChange={(event, value) => {
setNewValue(value);
textToggleState(!textToggle);
}}
autoSelect={true}
getOptionLabel={(option) =>
`${option.country}` + `+ ${option.calling_code}`
}
renderOption={(option) => (
<>{`${option.country} + ${option.calling_code}`}</>
)}
//defaultValue={cities[98]}
style={{ width: "100%" }}
renderInput={(params) => (
<TextField
{...params}
variant="standard"
placeholder="Search your country"
style={{ width: "40%" }}
/>
)}
/>
) : (
""
)}
)
Following is the CodeSandbox link: https://codesandbox.io/s/how-to-add-only-single-value-from-autocomplete-in-material-ui-forked-tu218
You can pass a value prop to autocomplete component with the newValue. But newValue is an empty object by default that doesn't exist in the options array you are passing to the autocomplete so it will show undefined + undefined in the default case. You can make that null and add null check there in the autocomplete itself or you can assign a value directly in your useState So as you are having a check for null and using 91 code so instead you can assign that value to the newValue itself directly. Check the code below I have added the value field here
<Autocomplete
id="size-small-standard"
size="small"
options={cities}
value={newValue !== null ? newValue : cities[98]}
onChange={(event, value) => {
setNewValue(value);
textToggleState(!textToggle);
}}
autoSelect={true}
getOptionLabel={(option) =>
`${option.country}` + `+ ${option.calling_code}`
}
renderOption={(option) => (
<>{`${option.country} + ${option.calling_code}`}</>
)}
//defaultValue={cities[98]}
style={{ width: "100%" }}
renderInput={(params) => (
<TextField
{...params}
variant="standard"
placeholder="Search your country"
style={{ width: "40%" }}
/>
)}
/>
Or you can just pass newValue to the value field and assign the default value in the newValue useState as shown below
const [newValue, setNewValue] = useState(cities[98]);
.
.
.
.
<Autocomplete
id="size-small-standard"
size="small"
options={cities}
value={newValue}
onChange={(event, value) => {
setNewValue(value);
textToggleState(!textToggle);
}}
autoSelect={true}
getOptionLabel={(option) =>
`${option.country}` + `+ ${option.calling_code}`
}
renderOption={(option) => (
<>{`${option.country} + ${option.calling_code}`}</>
)}
//defaultValue={cities[98]}
style={{ width: "100%" }}
renderInput={(params) => (
<TextField
{...params}
variant="standard"
placeholder="Search your country"
style={{ width: "40%" }}
/>
)}
/>
Related
i'm trying to display results with the MUI Autocomplete component but i need to
separate them in two different list side by side.
I currently have a functionnal searchbar with one list, but i want to separate the results based on a specific property from each option who will refer as their type.
Here's what i have as a beginner :
<Autocomplete
freeSolo={true}
id="equipment-searchbar"
onOpen={() => {
setOpen(true);
}}
onClose={() => {
setOpen(false);
}}
clearOnBlur={false}
isOptionEqualToValue={(option, value) => option.name === value.name}
getOptionLabel={(option) => option.title || ''}
filterOptions={x => x}
options={options}
groupBy={(option) => option.type}
onInputChange={onInputChange}
open={open}
onChange={(event: any, option: any) => {
let searchData = (document.getElementById("equipment-searchbar") as HTMLInputElement).value
if (option !== null && option.globalSearch !== true) {
switch (option.type) {
case bikeSmooveboxType:
redirect("bike/" + option.title)
break;
case stationTransmiterType:
redirect("station/" + option.code)
break;
}
}
}}
loading={loading}
renderInput={(params) => (
<TextField
className="inputRounded"
variant="outlined"
label={"Rechercher dans les équipements"}
{...params}
InputProps={{
...params.InputProps,
endAdornment: (
<React.Fragment>
<SearchIcon/>
{params.InputProps.endAdornment}
</React.Fragment>
),
}}
/>
)}
/>
Any suggestions for solving this problem ?
Thank's a lot !
Basically what you need to do is:
use renderGroup prop and put your jsx for columns.
use ListboxProps prop to apply display:flex for the results.
if needed you can check out PaperComponent and PopperComponent for further customization.
This is a snippet of what probably you need:
<Autocomplete
renderGroup={(item) => {
const { group, children } = item;
if (group === "type1")
return (
<Box
sx={{ width: "50%" }}
/*custom props for type 1*/
>
{children}
</Box>
);
return (
<Box
sx={{ width: "50%" }}
/*custom props for type 2*/
>
{children}
</Box>
);
}}
ListboxProps={{
sx: { display: "flex" },
}}
/>
<StyledAutocomplete
sx={{ width: "40%", ml: "10px", mr: "10px" }}
id='multiple-limit-tags'
options={locationOptions}
filterSelectedOptions
autoComplete={true}
onChange={handleLocationChange}
getOptionLabel={option => option.label}
freeSolo
autoHighlight
forcePopupIcon
autoFocus
renderTags={(value, getTagProps) =>
value.map((option, index) => (
<Chip key={index} variant='filled' label={option} {...getTagProps({ index })} />
))
}
renderInput={params => (
<TextField
{...params}
variant='outlined'
label='Location'
placeholder={selectedLocations.length < 1 ? "Country" : ""}
/>
)}
/>
I wanna be able to render the input into a chip without multiple prop, the renderTags props only seems to work on multiple
I have an Autocomplete component for adding country calling code, but, the relevant country is added too with it. Like when clicked on Autocomplete drop-down list, all the countries and its specific codes are displayed. My intention is to add only the country code. See the code below for reference
const [countryData, setCountryData] = useState({});
const [newValue, setNewValue] = useState("");
useEffect(() => {
setCountryData(codes);
}, []);
<Autocomplete
id="size-small-standard"
size="small"
options={cities}
onChange={(event, value) => setNewValue(value)}
autoSelect={true}
getOptionLabel={(option) =>
option.country + " " + ` +` + option.calling_code {/* <-- How to display only calling code, but, should show both country name and calling code in drop down */}
}
defaultValue={cities[98]}
style={{ width: "100%" }}
renderInput={(params) => (
<TextField
{...params}
variant="standard"
placeholder="Search your country"
style={{ width: "40%" }}
/>
)}
/>
What would be best possible solution?
Following is the CodeSandbox link: https://codesandbox.io/s/material-demo-forked-3ljj2
You can change your getOptionLabel to show only the phone prefix and then use renderOption to show the name with the country's phone prefix
return (
<div className={classes.root}>
<Autocomplete
id="size-small-standard"
size="small"
options={cities}
onChange={(event, value) => setNewValue(value)}
autoSelect={true}
getOptionLabel={(option) => `+ ${option.calling_code}`}
renderOption={(option) => (
<>{`${option.country} + ${option.calling_code}`}</>
)}
defaultValue={cities[98]}
style={{ width: "100%" }}
renderInput={(params) => (
<TextField
{...params}
variant="standard"
placeholder="Search your country"
style={{ width: "40%" }}
/>
)}
/>
</div>
);
Live Demo
UPDATE:
Here is a better example, where you can still search for the country.
Live Demo
In an Autocomplete Form, the data for country and its relevant codes are displayed. When the input text is focused the drop-down list is populated. My intention is to pre load array of data without focus requirement. See the code for example
const [newValue, setNewValue] = useState(null);
const [textToggle, textToggleState] = useState(false);
render(
<div
style={{ cursor: "pointer" }}
onClick={() => {
textToggleState(!textToggle);
}}
>
<h5>+{newValue == null ? "91" : newValue.calling_code}</h5>
</div>
{textToggle ? (
<Autocomplete
id="size-small-standard"
size="small"
options={cities}
onChange={(event, value) => {
setNewValue(value);
textToggleState(!textToggle);
}}
autoSelect={true}
getOptionLabel={(option) =>
`${option.country}` + `+ ${option.calling_code}`
}
renderOption={(option) => (
<>{`${option.country} + ${option.calling_code}`}</>
)}
//defaultValue={cities[98]}
style={{ width: "100%" }}
renderInput={(params) => (
<TextField
{...params}
variant="standard"
placeholder="Search your country"
style={{ width: "40%" }}
/>
)}
/>
) : (
""
)}
</div>
)
Here you can see data is displayed on input text focus. What could be the best possible solution to
pre-load data?
CodeSandbox Link: https://codesandbox.io/s/how-to-add-only-single-value-from-autocomplete-in-material-ui-forked-tu218
Just take control of the open state of the Autocomplete and set the default value to true:
export default function ComboBox() {
// default value to true to open at first render
const [open, setOpen] = useState(true);
return (
<Autocomplete
open={open}
onOpen={() => setOpen(true)}
onClose={() => setOpen(false)}
options={top100Films}
getOptionLabel={(option) => option.title}
renderInput={(params) => (
<TextField {...params} label="Combo box" variant="outlined" />
)}
/>
);
}
Live Demo
I think what you need is to use AutoComplete as Combobox.
<Autocomplete
id="combo-box-demo"
options={top100Films}
getOptionLabel={(option) => option.title}
style={{ width: 300 }}
renderInput={(params) => <TextField {...params} label="Combo box" variant="outlined" />}
/>
This will pre-populate it.
Visit this: https://material-ui.com/components/autocomplete/#combo-box
Hope it helps. if not, please elaborate your question if you want something else.
How is possible to add onClick event on the options - i mean when u click the selected option i want to link somewhere, not to just put in the searchField(or textField)? I search really hard on the web, but i just cant find how to do that.
<Autocomplete
freeSolo
classes={classes}
options={searchItems}
getOptionLabel={(option) =>
option.title ? option.title : option.name
}
style={{ width: 300, borderRight: "none", borderLeft: "none" }}
renderInput={(params) => {
return (
<TextField
{...params}
variant="outlined"
fullWidth
placeholder="Search for movie, tv or person"
value={value}
onChange={(e) => handleChange(e)}
/>
);
}}
/>
You need to move the onChange function inside the Autocomplete component as below:
<Autocomplete
id="combo-box-demo"
classes={classes}
options={searchItems}
getOptionLabel={(option) =>
option.title ? option.title : option.name
}
style={{ width: 300, borderRight: "none", borderLeft: "none" }}
onChange={(e, value) => console.log(e.target, value.title)}
renderInput={(params) => (
<TextField {...params} label="Combo box" variant="outlined" />
)}
/>
Here is an example that I have created. When the onChange function in the Autocomplete component is triggered, it displays values on the console. According to the doc, onchange function here pass three props called event, value and reason.