How to add Icon to MobileDatePicker in MUI v5 - reactjs

This is part of the code:
<MobileDatePicker
showTodayButton
showToolbar={false}
disableCloseOnSelect={false}
inputFormat="YYYY-MM-DD"
views={['day']}
value={row.value}
onChange={(newValue) => row.onChange(newValue)}
renderInput={(params) => (
<InputBase {...params} className={classes.datePicker} />
)}
/>
On the mobile side, he does not show trigger Icon.
How to display to give users a clear indication.

The MobileDatePicker doesn't have a suffix icon because you can open it by focusing the TextField unlike the DesktopDatePicker where you have to click the icon to open the picker. But if you still want to include the icon anyway, just add one in the endAdornment of the TextField:
import InputAdornment from '#mui/material/InputAdornment';
import EventIcon from '#mui/icons-material/Event';
const [value, setValue] = React.useState<Date | null>(new Date());
const [open, setOpen] = React.useState(false);
const handleOpen = () => setOpen(true);
const handleClose = () => setOpen(false);
return (
<MobileDatePicker
label="For mobile"
value={value}
open={open}
onOpen={handleOpen}
onClose={handleClose}
onChange={setValue}
renderInput={(params) => (
<TextField
{...params}
InputProps={{
endAdornment: (
<InputAdornment position="end">
<IconButton edge="end" onClick={handleOpen}>
<EventIcon />
</IconButton>
</InputAdornment>
),
}}
/>
)}
/>
);
Related answer
How to change the icon in MUI DatePicker?

Related

React MUI Issue - Clicking on InputAdornment doesn't open the Popup

I'm using the Autocomplete component as in the country example, but decorated with the InputAdornment component in order to show the flag of the select country.
Here the working code:
The problem: after picking a country, if the user clicks exactly on the flag, country's name is selected. And, if the user clicks on the remaining part of the Autocomplete, the Popper is showing up (as expected and that's totally ok).
Current behaviour:
MY GOAL: I'd like to open the Autocomplete Popper even when clicking on the flag.
Expected behaviour:
I tried to use the option disablePointerEvents in the InputAdornment parameters, but nothing changed.
I tried the same on a pure Textfield MUI component and it worked, so it maybe it is something related to Autocomplete only.
Is there a workaround for this issue?
Same issue here
One solution is to control the open state of the Autocomplete using the open, onOpen, and onClose props and then add an onClick (instead of disablePointerEvents) to the InputAdornment to open the Autocomplete.
Here is a working example based on your sandbox:
import * as React from "react";
import Box from "#mui/material/Box";
import TextField from "#mui/material/TextField";
import Autocomplete from "#mui/material/Autocomplete";
import InputAdornment from "#mui/material/InputAdornment";
export default function CountrySelect() {
const [value, setValue] = React.useState(null);
const [open, setOpen] = React.useState(false);
return (
<Autocomplete
id="country-select-demo"
value={value}
onChange={(event, newValue) => {
setValue(newValue);
}}
sx={{ width: 300 }}
options={countries}
autoHighlight
open={open}
onOpen={() => setOpen(true)}
onClose={() => setOpen(false)}
getOptionLabel={(option) => option.label}
renderOption={(props, option) => (
<Box
component="li"
sx={{ "& > img": { mr: 2, flexShrink: 0 } }}
{...props}
>
<img
loading="lazy"
width="20"
src={`https://flagcdn.com/w20/${option.code.toLowerCase()}.png`}
srcSet={`https://flagcdn.com/w40/${option.code.toLowerCase()}.png 2x`}
alt=""
/>
{option.label} ({option.code}) +{option.phone}
</Box>
)}
renderInput={(params) => (
<TextField
{...params}
label="Choose a country"
inputProps={{
...params.inputProps,
autoComplete: "new-password" // disable autocomplete and autofill
}}
InputProps={{
...params.InputProps,
startAdornment: value ? (
<InputAdornment position="start" onClick={() => setOpen(true)}>
<img
loading="lazy"
width="48"
src={`https://flagcdn.com/w20/${value.code.toLowerCase()}.png`}
srcSet={`https://flagcdn.com/w40/${value.code.toLowerCase()}.png 2x`}
alt=""
/>
</InputAdornment>
) : null
}}
/>
)}
/>
);
}

In autocomplete from materials ui how can I can click a button and clear the autocomplete like make it empty

The autocomplete looks like this
<Autocomplete options={speceificLocation.locationOptions} onChange = {(event,value) => (speceificLocation.locationOptions.includes(value)) ? dispatch({allCities:state.allCities, mappedCities:true}):dispatch({allCities:state.allCities, mappedCities:false})} renderInput = {(params) => <TextField {...params} label = 'Cities'/>}/>
Here is a live demo of an Autocomplete that can be cleared by a button.
import * as React from "react";
import Button from "#mui/material/Button";
import TextField from "#mui/material/TextField";
import Autocomplete from "#mui/material/Autocomplete";
const options = ["Option 1", "Option 2"];
export default function ControllableStates() {
const [value, setValue] = React.useState<string | null>(options[0]);
const [inputValue, setInputValue] = React.useState("");
return (
<div>
<div>{`value: ${value !== null ? `'${value}'` : "null"}`}</div>
<div>{`inputValue: '${inputValue}'`}</div>
<br />
<Button onClick={() => setValue("")}>Clear</Button>
<br />
<br />
<Autocomplete
value={value}
onChange={(event: any, newValue: string | null) => {
setValue(newValue);
}}
inputValue={inputValue}
onInputChange={(event, newInputValue) => {
setInputValue(newInputValue);
}}
id="controllable-states-demo"
options={options}
sx={{ width: 300 }}
renderInput={(params) => <TextField {...params} label="Controllable" />}
/>
</div>
);
}

Make options of Material-ui autocomplete component clickable links?

import React, { useEffect, useRef } from "react";
import TextField from "#material-ui/core/TextField";
import Autocomplete from "#material-ui/lab/Autocomplete";
export default function FreeSolo(props) {
const [vendors, setVendors] = React.useState([]);
const [value, setValue] = React.useState();
const nameRef = useRef();
useEffect(() => {
sendDataToParent();
}, [value]);
const sendDataToParent = async () => {
await props.parentFunction(value);
};
return (
<div style={{}}>
<Autocomplete
freeSolo
id="free-solo-2-demo"
options={props.vendorData.map((option) => option.name)}
renderInput={(params) => (
<TextField
{...params}
value={value}
required
inputRef={nameRef}
onChange={(e) => {
setValue(e.target.value);
sendDataToParent();
}}
label="Vendor Name"
margin="normal"
variant="standard"
InputProps={{ ...params.InputProps, type: "search" }}
/>
)}
/>
</div>
);
}
I tried to do it using renderOption but could not get it working. I need to have the options to be clickable links so that whenever user selects of the options, he is redirected to the link.
EDIT: Solved using renderOption
renderOption={(option) => (
<React.Fragment>
<span
style={{ cursor: "pointer" }}
onClick={() => {
window.location.href = `/allvendors/${option.id}`;
}}
>
{option.name} - Click to visit the Vendor
</span>
</React.Fragment>
)}
Instead of making the options clickable links, you can redirect to the link using the onChange prop of the Autocomplete component.
I'm assuming each option in your vendorData has a name and also a link e.g.
{
name: "Google",
link: "https://www.google.com"
}
To be able to access the link from this object in the Autocomplete component's onChange, you'll need to change the options map function to return the whole option. After this change, if you try to click to open the dropdown, it will throw an error because the option label needs to be a string (e.g. the option name) and not an object (e.g. option). So, we need to add the getOptionLabel prop and return the option.name.
Finally, in the onChange function, we set the window.location.href equal to the option.link, which changes the current page's URL to the link and directs the user to that link.
<div style={{}}>
<Autocomplete
freeSolo
id="free-solo-2-demo"
getOptionLabel={(option) => option.name}
options={props.vendorData.map((option) => option)}
onChange={(event: any, option: any) => {
window.location.href = option.link;
}}
renderInput={(params) => (
<TextField
{...params}
value={value}
required
inputRef={nameRef}
onChange={(e) => {
setValue(e.target.value);
sendDataToParent();
}}
label="Vendor Name"
margin="normal"
variant="standard"
InputProps={{ ...params.InputProps, type: "search" }}
/>
)}
/>
</div>

Multiple autocomplete fields with Material UI in same view

I have 2 autocomplete fields on my view by default, but you can add more fields per click.
Currently I have the problem that every autocomplete field opens every result list of every autocomplete field, because every field uses "open". How do I get it to implement the whole thing dynamically?
const [value, setValue] = useState<string>('')
const [open, setOpen] = useState(false)
<Autocomplete
options={props.results.map((option) => option.name)}
renderOption={(option) => (
<Typography noWrap>
{option}
</Typography>
)}
onClose={() => {
setOpen(false)
}}
open={open}
renderInput={(params) => (
<Paper className={search.root} ref={params.InputProps.ref}>
<IconButton className={search.iconButton} disabled>
<FiberManualRecordIcon color="secondary" />
</IconButton>
<InputBase
{...params.inputProps}
className={search.input}
placeholder="Test"
value={value}
onChange={(event: any) => setValue(event.target.value)}
/>
<IconButton
className={search.iconButton}
disabled={!value}
>
<SearchIcon />
</IconButton>
</Paper>
)}
/>
Probably you already solved this due to the date of this issue. But I'm gonna put here what I did to resolve this problem because I was facing the same issue using FieldArray from Formik.
Material UI documentation sometimes is a little confusing, so try to ignore some stuff in their examples.
Remove the open, onOpen, and onClose props. You just need these props if you want to create some kind of automatic opening/closing mechanic.
Here it's an example of what I was doing and how I solved it.
<Autocomplete
id={`items.${index}.partNumber`}
name={`items.${index}.partNumber`}
freeSolo
style={{ width: 300 }}
open={openPartNumber}
onOpen={() => setOpenPartNumber(true)}
onClose={() => setOpenPartNumber(false)}
options={partNumbers}
clearOnBlur={false}
getOptionLabel={option => (option.label ? option.label : '')}
value={item.partNumber}
inputValue={item.partNumber}
onInputChange={(event, newInputValue) => {
if (event) {
setFieldValue(`items.${index}.partNumber`, newInputValue);
getPartNumberList(newInputValue);
}
}}
onChange={(event, optionSelected, reasson) => {
if (reasson === 'select-option') {
setFieldValue(`items.${index}.partNumber`, optionSelected.partNumber);
setFieldValue(`items.${index}.vendorNumber`, optionSelected.vendorNumber);
setFieldValue(`items.${index}.description`, optionSelected.description);
setFieldValue(`items.${index}.ncm`, optionSelected.ncm);
}
}}
filterOptions={x => x}
...otherPrps...
/>
Then I just remove the props open, onOpen and onClose.
<Autocomplete
id={`items.${index}.partNumber`}
name={`items.${index}.partNumber`}
freeSolo
style={{ width: 300 }}
options={partNumbers}
clearOnBlur={false}
getOptionLabel={option => (option.label ? option.label : '')}
value={item.partNumber}
inputValue={item.partNumber}
onInputChange={(event, newInputValue) => {
if (event) {
setFieldValue(`items.${index}.partNumber`, newInputValue);
getPartNumberList(newInputValue);
}
}}
onChange={(event, optionSelected, reasson) => {
if (reasson === 'select-option') {
setFieldValue(`items.${index}.partNumber`, optionSelected.partNumber);
setFieldValue(`items.${index}.vendorNumber`, optionSelected.vendorNumber);
setFieldValue(`items.${index}.description`, optionSelected.description);
setFieldValue(`items.${index}.ncm`, optionSelected.ncm);
}
}}
filterOptions={x => x}
...otherPrps...
/>
If you want automatic opening/closing mechanics to exist. One suggestion is to control open starting from an array.
In the onOpen and onClose props, your callback must control an array by adding and removing the AutoComplete ID and in open just check the existence of this ID inside the array with array.includes(index).
const [value, setValue] = useState<string>('')
//const [open, setOpen] = useState(false)
const [inputsOpen, setInputsOpen] = useState([])
function automatedOpening(id) {
if (id && inputsOpen.length === 0) {
setInputsOpen([...inputsOpen, id]);
}
}
// lenght must be zero to ensure that no other autocompletes are open and will be true on the Open prop
function automatedClosing(id) {
if (id && inputsOpen.length !== 0) {
setInputsOpen(inputsOpen.filter(item => item !== id));
}
}
<Autocomplete
options={props.results.map((option) => option.name)}
renderOption={(option) => (
<Typography noWrap>
{option}
</Typography>
)}
onClose={(e) => automatedClosing(e.id)}
onOpen={(e) => automatedClosing(e.id)}
open={inputsOpen.includs(id)}
renderInput={(params) => (
<Paper className={search.root} ref={params.InputProps.ref}>
<IconButton className={search.iconButton} disabled>
<FiberManualRecordIcon color="secondary" />
</IconButton>
<InputBase
{...params.inputProps}
className={search.input}
placeholder="Test"
value={value}
onChange={(event: any) => setValue(event.target.value)}
/>
<IconButton
className={search.iconButton}
disabled={!value}
>
<SearchIcon />
</IconButton>
</Paper>
)}
/>
you'll probably need to find a way to make the id/index available to the callbacks, but it's open to what you think is best

How to clear the autocomplete's input in Material-ui after an onChange?

In the hooks version of material UI I can't seem to be able to clear the autocomplete after an onChange event:
// #flow
import React, { useRef, useState } from "react";
import "./Autocomplete.scss";
import AutocompleteUI from "#material-ui/lab/Autocomplete";
import TextField from "#material-ui/core/TextField";
function Autocomplete(props) {
const { options } = props;
const [value, setValue] = useState();
const container = useRef();
const input = useRef();
function onChange(event, newValue) {
if (!newValue) return;
props.onChange(newValue);
setValue(undefined);
input.current.value = "";
event.target.value = "";
}
function renderInput(params) {
return (
<TextField
inputRef={input}
{...params}
inputProps={{
...params.inputProps,
autoComplete: "disabled", // disable autocomplete and autofill
}}
margin="none"
fullWidth
/>
);
}
return (
<div className="Autocomplete-container">
{value}
<AutocompleteUI
ref={container}
options={options}
autoHightlight={true}
clearOnEscape={true}
autoSelect={true}
// freeSolo={true}
getOptionLabel={option => option.title}
renderInput={renderInput}
value={value}
onChange={onChange}
/>
</div>
);
}
export default Autocomplete;
Diving into the source code I've noticed the component uses useAutocomplete hook internally. However, neither setInputValue nor resetInputValue which live internally inside that hook are exposed outside. Is there a way to accomplish an input clear after an onChange?
You need to set the inputValue prop to your valueState and on onhange function just clear the valueState
<Autocomplete
inputValue={valueState}
onChange={(value, option) =>
{
setOptions([])
setValueState("")
}}
renderInput={params => (
<TextField
dir="rtl"
onChange={(event) =>
{
setValueState(event.target.value)
}}
{...params}
label="Search Patient"
variant="filled"
InputProps={{
...params.InputProps,
endAdornment: (
<React.Fragment>
{loading ? (
<CircularProgress color="inherit" size={20} />
) : null}
{params.InputProps.endAdornment}
</React.Fragment>
)
}}
/>
)}
/>
I had the same issue and I solved it with this :
const [search, setSearch] = useState("");
...
<Autocomplete
id="grouped-demo"
options={tagsList}
getOptionLabel={(option) => option.tag}
onChange={(event, value) =>value ? setSearch(value.tag) : setSearch(event.target.value)}
style={{width: 700}}
renderInput={(params) => <TextField {...params} label="Search" variant="outlined"/>}
/>
I encountered a similar scenario using Autocomplete/Textfield in a Search/Nav bar. The value would always be left behind after using a history.push or other Router function in the onChange event. The trick is to set the inputValue = "" . Every time the component renders, the previous value will be removed. See below
<Autocomplete
{...defaultProps}
onChange={(event, value) => {
if(value)
router.history.push(`/summary`);
}}
filterOptions={filterOptions}
clearOnEscape={true}
inputValue=""
renderInput={params => <TextField {...params}
label="Quick Search" fullWidth
InputProps={{...params.InputProps,
'aria-label': 'description',
disableUnderline: true,
}}/>}
/>
yo! I'm pretty sure the Textfield component from material takes an "autoComplete" prop, and you can pass that the string "false". Also, it does not go in inputProps, try that out.
<Textfield autoComplete="false" />
I had the same issue and I solved it with this :
const [value, setValue] = useState(null);
Then you don't need to use refs.

Resources