Reputation: 545
I am trying to work using the Autocomplete component using Material-UI, and for some reason, the close icon does not show when I update some text.
I split the Autocomplete component up by display and with a wrapper that actually makes the API request on text change. I have tried specifying the closeIcon
prop, but cannot get it to show up.
Display Component:
import React from 'react';
import { faPodcast, faSearch, faUser } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Grid } from '@material-ui/core';
import Box from '@material-ui/core/Box';
import InputAdornment from '@material-ui/core/InputAdornment';
import TextField from '@material-ui/core/TextField';
import Typography from '@material-ui/core/Typography';
import { Autocomplete } from '@material-ui/lab';
function SearchBarDisplay({ options = [], onChange, onSelectValue, text }) {
function getOptionLabel(option) {
if (option.name) {
return option.name;
} else if (option.username) {
return option.username;
} else if (option.type === 'advanced') {
return option.text;
} else {
return null;
}
}
function renderOption(name, username, type) {
if (name) {
return (
<Grid container alignItems="center" wrap="nowrap">
<Box mr={1}>
<FontAwesomeIcon icon={faPodcast} />
</Box>
<Typography noWrap>{name}</Typography>
</Grid>
);
} else if (username) {
return (
<Grid container alignItems="center" wrap="nowrap">
<Box mr={1}>
<FontAwesomeIcon icon={faUser} />
</Box>
<Typography noWrap>{username}</Typography>
</Grid>
);
} else if (type === 'advanced') {
return (
<Grid container alignItems="center" wrap="nowrap">
<Box mr={1}>
<FontAwesomeIcon icon={faSearch} />
</Box>
<Typography
noWrap={true}
color="textSecondary">{`See more results for "${text}"`}</Typography>
</Grid>
);
} else {
return null;
}
}
return (
<Autocomplete
id="autocomplete"
options={text.replace(/\s/g, '').length ? options : []}
popupIcon={null}
getOptionSelected={(option, value) => option._id === value._id}
getOptionLabel={(option) => getOptionLabel(option)}
onChange={(event, value) => onSelectValue(value)}
onInputChange={(event, value) => onChange(value)}
renderOption={({ name, username, type }) => renderOption(name, username, type)}
renderInput={(params) => (
<TextField
{...params}
placeholder="Search for podcasts or TapTapers"
margin="normal"
variant="outlined"
InputProps={{
...params.InputProps,
startAdornment: (
<InputAdornment position="start">
<FontAwesomeIcon icon={faSearch} />
</InputAdornment>
)
}}
/>
)}
/>
);
}
export default SearchBarDisplay;
Wrapper to make API requests and pass in options/current text value:
import React, { useEffect, useMemo, useState } from 'react';
import axios from 'axios';
import { debounce } from 'lodash';
import { useRouter } from 'next/router';
import SearchBarDisplay from './display';
function SearchBar() {
const router = useRouter();
const [options, setOptions] = useState([]);
const [text, setText] = useState('');
async function getSearch(text) {
await axios.get(`/api/search/${text}`).then(({ data }) => {
if (Object.keys(data).length === 0 || text.trim().length === 0) {
setOptions([]);
} else {
setOptions([...data, ...[{ type: 'advanced', text: text }]]);
}
});
}
function routeOnSubmit(value) {
const { username, _id, name, type, text } = value || {};
if (username) {
router.push({
pathname: '/users/[id]',
query: { id: _id }
});
} else if (name) {
router.push({
pathname: '/podcasts/[id]',
query: { id: _id }
});
} else if (type === 'advanced') {
router.push({
pathname: 'search/advanced/[text]',
query: { text }
});
}
}
const debouncedGetSearch = useMemo(() => debounce(getSearch, 500), []);
useEffect(() => {
if (text.replace(/\s/g, '').length) {
debouncedGetSearch(text);
} else {
setOptions([]);
}
}, [text, debouncedGetSearch]);
return (
<SearchBarDisplay
options={options}
onSelectValue={(value) => routeOnSubmit(value)}
text={text}
onChange={(value) => setText(value)}
/>
);
}
export default SearchBar;
Upvotes: 1
Views: 1159
Reputation: 545
I was able to fix this! I wanted the close icon to appear when you typed, and I needed to pass in the freeSolo
prop as per the Material-UI documentation.
Upvotes: 1