MUI TextField Select with grouping has no functionality - reactjs

I have an MUI TextField Select that has optgroups. I already tried a native Select, which didn't allow for the css customization I need for the dropdown menu.
Below is a simplified version of the code:
options = { group1: ['o1','o2','o3'], group2: ['o3','o4','o5'] }
<TextField
select
onChange={(e) => handleChange(e)} // <<< This doesn't work
>
{ options && Object.entries(options).map( ( [k,v] ) => { return (
<Box key={k + 'optgroup'}> // <<< I think this is why. What should this be?
<MenuItem
disabled
data-type='optgroup'
>
{k}
</MenuItem>
v.map( (ov:string,oi:number) => {
return (
<MenuItem
key={ov+oi}
data-type='option'
>
{ov}
</MenuItem>
)
})
</Box>
)})}
</TextField>
The example above has no functionality - the onChange does nothing, I changed it to be an onClick on the MenuItem - but that doesn't close the menu.
Question: What is the correct way to build a non-native MUI Select with grouping?

Related

How can I hide an image in a material ui custom select when that menu item is selected?

I have a material ui (v4) custom select and I wanted a delete option for custom created statuses. The last 2 are deleteable.
However, Once selected I no longer want the delete image there...
Here's my overrided select...
<Select>
{items?.map(({ value, label }) => (
<MenuItem
classes={{
root: classes.selectMenuItem,
selected: classes.selectMenuItemSelected
}}
value={value}
key={value || Math.random()}
>
{ deleteable && value > 11 && (
<ListItemIcon>
<DeleteForeverRoundedIcon />
</ListItemIcon>
)}
{label || value}
</MenuItem>
))}
</Select>
and my custom select...
<CustomSelect
value={leadStatus}
leadStatus={leadStatus}
onChange={e => {
setLeadStatus(e.target.value);
}}
data={defaultLeadStatuses}
deleteable={true}
/>
Appreciate any guidance!

onChange in Material UI Menu component

thanks for being here! My question is related to how I can create an 'onChange' property in the Material UI Menu component. When I am using the 'onChange' property of the Select component, I can easily alter my state after the user clicks on it. I would like to create a similar effect, but then using a Menu instead of a Select component. Note that I am using a function inside a hook, which might complicate things.
Below I could show you how an example of how my code looks:
const [sortingMethod, setSortingMethod] = useState(() => sortHighestSummerTemp);
const onSortMethod = (e) => {
setSortingMethod(e.target.value);
};
<FormControl>
<InputLabel shrink>Sort By </InputLabel>{' '}
<Select defaultValue="" onChange={onSortMethod}>
<MenuItem value={() => sortHighestSummerTemp}>☀️ Hottest summers</MenuItem>
<MenuItem value={() => sortLowestWinterTemp}>🥶 Coldest winters</MenuItem>
<MenuItem value={() => sortMostHotDays}>🥵 Most hot days</MenuItem>
</Select>
</FormControl>;
That's my select component in action, which is working. And here is the same Menu, where I don't know how to implement the "onChange":
<FormControl className={classes.formControl}>
<PopupState variant="popover" popupId="demo-popup-menu">
{(popupState) => (
<React.Fragment>
<Button
variant="contained"
color="primary"
startIcon={<SortIcon />}
{...bindTrigger(popupState)}
>
Sort by
</Button>
<Menu
value=""
// onChange={onSortMethod} <-- How to do this? ⚠
{...bindMenu(popupState)}
>
<MenuItem
onClick={popupState.close}
value={() => sortHighestSummerTemp}
>
☀️ Hottest summers
</MenuItem>
<MenuItem
onClick={popupState.close}
value={() => sortLowestWinterTemp}
>
🥶 Coldest winters
</MenuItem>
<MenuItem onClick={popupState.close} value={() => sortMostHotDays}>
🥵 Most hot days
</MenuItem>
</Menu>
</React.Fragment>
)}
</PopupState>
</FormControl>;
I would be blessed if you could explain how to achieve a similar effect with the Menu component!
Thank you for reading.
I think you should do that per MenuItem (at the onClick property). The Menu itself doesn't have that kind of property: Material-UI page
Secondly, I don't like value as a function. I think you can just pass the variable (sortHighestSummerTemp or sortLowestWinterTemp) to a state. React page reference

Label of React material-ui Select component displays over content

I have the following material-ui Select component:
<FormControl fullWidth className="attr-foreign-key">
<InputLabel id={field+"-label"}>{catalog.title_singular}</InputLabel>
<Select
labelId={field+"-label"}
id={field}
value={value_name}
onChange={this.handleChange(value_id)}
renderValue={value_name => value_name}
>
<MenuItem value="">
<em>Ninguno</em>
</MenuItem>
{
this.state.choices? this.state.choices.map(choice => <MenuItem value={choice.name}>{choice.name}</MenuItem>): null
}
</Select>
</FormControl>
The problem is that it displays the label of the Select over its content:
It only displays well when the Select has the focus:
But it fails again when it looses it. I haven't found any reference for solving this.
Material ui has a props in Textfield component to transform it to use select. Doing so you wont have the problem and it will be easier for you to use for the same result.
link
Code sample:
<TextField
id="filled-select-currency"
select
label="Select"
value={currency}
onChange={handleChange}
helperText="Please select your currency"
variant="filled"
>
{currencies.map(option => (
<MenuItem key={option.value} value={option.value}>
{option.label}
</MenuItem>
))}
</TextField>
Hope it helps.

onClick on MenuItem not fired

I am using redux form with material ui. I have an array of form templates that are available to select as options. What I am trying to achieve is to get the selected template back, dispatch an action and then initialize redux form with selected template values. I am unable to call the method on SelectItem component (nothing gets logged to the console). I went through the similar problems and solutions but nothing seemed to work in my case. My code goes like this:
setTemplate = (option) => {
console.log(option);}
{formTemplates && (
<Row>
<StyledFormControl>
<Field name="templates" label="Available templates:" component={SelectField}>
<MenuItem value="" disabled>
Choose template:
</MenuItem>
{formTemplates.map(option => {
return (
<MenuItem value={option._id} onClick={this.setTemplate.bind(this, option)} key={option._id}>
{option._id}
</MenuItem>
);
})}
</Field>
</StyledFormControl>
</Row>
)}
Do you have any idea why this should not work? Thanks
try
onClick={() => this.setTemplate(option).bind(this)}

How to set default value in material-UI select box in react?

I am using Select box from material-ui
I want to show "select the value" option by default selected but after that user is not able to select this option.
<FormControl required className={classes.formControl}>
<InputLabel htmlFor="circle">Circle</InputLabel>
<Select
value={circle}
onChange={event => handleInput(event, "circle")}
input={<Input name="circle" id="circle" />}
>
<MenuItem value="" disabled>
<em>select the value</em>
</MenuItem>
<MenuItem value={10}>Ten</MenuItem>
<MenuItem value={20}>Twenty</MenuItem>
<MenuItem value={30}>Thirty</MenuItem>
</Select>
<FormHelperText>Some important helper text</FormHelperText>
</FormControl>
Current code on sandbox: https://codesandbox.io/s/xoylmlj1qp
I want to make like this: https://jsfiddle.net/wc1mxdto/
Update
I changed the state 20 to blank string in circle
form: {
searchValue: "",
circle: '',
searchCriteria: ""
}
now expected output should be dropdown should show "please select value" but currently it showing this
You need to provide correct MenuItem value in state to be matched on render.
Here is the working codesandbox: Default Select Value Material-UI
You can just pass the displayEmpty into select
<Select
id="demo-simple-select-outlined"
displayEmpty
value={select}
onChange={handleChange}
>
and define the menuItem like
<MenuItem value=""><Put any default Value which you want to show></MenuItem>
As React introduced React-Hooks, you just need to pass your default value in React.useState() as React.useState(10).
export default function CustomizedSelects() {
const classes = useStyles();
const [age, setAge] = React.useState(10);// <--------------(Like this).
const handleChange = event => {
setAge(event.target.value);
};
return (
<form className={classes.root} autoComplete="off">
<FormControl className={classes.margin}>
<Select
value={age}
className={classes.inner}
onChange={handleChange}
input={<BootstrapInput name="currency" id="currency-customized-select" />}
>
<MenuItem value={10}>Ten</MenuItem>
<MenuItem value={20}>Twenty</MenuItem>
<MenuItem value={30}>Thirty</MenuItem>
</Select>
</FormControl>
</form>
);
}
<FormControl variant="outlined" className={classes.formControl}>
<InputLabel id="uni">UNI</InputLabel>
<Select
key={value}
defaultValue={value}
labelId="uni"
id="uni"
name="uni"
onBlur={onChange}
label="uni"
>
{unis.map((u, i) => (
<MenuItem value={u.value} key={i}>
{u.label}
</MenuItem>
))}
</Select>
</FormControl>;
Just use the defaultValue attribute of select.
You can refer to the Material UI Select API Docs to know more.
import React from 'react';
import {useState} from 'react';
import FormControl from '#material-ui/core/FormControl';
import InputLabel from '#material-ui/core/InputLabel';
import Select from '#material-ui/core/Select';
import MenuItem from '#material-ui/core/MenuItem';
const Selector = () => {
const [Value, setValue] = useState("1"); // "1" is the default value in this scenario. Replace it with the default value that suits your needs.
const handleValueChange = event => {
setValue(event.target.value);
}
return(
<FormControl>
<InputLabel id="Input label">Select</InputLabel>
<Select
labelId= "Input label"
id= "Select"
value= {Value}
defaultValue= {Value}
onChange= {handleValueChange}
>
<MenuItem value="1">Item1</MenuItem>
<MenuItem value="2">Item2</MenuItem>
<MenuItem value="3">Item3</MenuItem>
</Select>
</FormControl>
)
};
export default Selector;
If you take a look at the Select Api of Material UI here, you could do it easily.
As explained above, you need to pass the default value in your state variable:
const [age, setAge] = React.useState(10);// <--------------(Like this).
Set displayEmpty to true:
If true, a value is displayed even if no items are selected.
In order to display a meaningful value, a function should be passed to the renderValue prop which returns the value to be displayed when no items are selected. You can only use it when the native prop is false (default).
<Select
displayEmpty
/>
I had a similar issue. In my case, I applied a function directly to onChange so I had something like this:
export default function CustomizedSelects() {
const classes = useStyles();
const [age, setAge] = React.useState(10);
return (
<form className={classes.root} autoComplete="off">
<FormControl className={classes.margin}>
<Select
value={age}
className={classes.inner}
onChange={(event) => setAge(event.target.value)}
input={<BootstrapInput name="currency" id="currency-customized-select" />}
>
<MenuItem value={10}>Ten</MenuItem>
<MenuItem value={20}>Twenty</MenuItem>
<MenuItem value={30}>Thirty</MenuItem>
</Select>
</FormControl>
</form>
);
}
I also had a separate button to clear select value (or select the default empty value). All was working, the select value was set correctly, except the Select component did not animate to its default form - when no value is selected. I fixed the problem by moving onChange to a handleChange separate function as it is in the code example #B4BIPIN is presenting.
I am not an expert in React and still learning and this was a good lesson. I hope this helps ;-)
Take a list of objects you want to display in the Select dropdown and initialise it using useState. Use the state now to show the value and update the state on the change of the dropdown.
const ackList = [
{
key: 0,
value: "Not acknowledged",
},
{
key: 1,
value: "Acknowledged",
},
];
function AcknowledgementList() {
//state to initialise the first from the list
const [acknowledge, setAcknowledge] = useState(ackList[1]);
//update the state's value on change
const handleChange2 = (event) => {
setAcknowledge(ackList[event.target.value]);
};
return (
<TextField
select
fullWidth
value={acknowledge.key}
onChange={handleChange2}
variant="outlined"
>
{ackList.map((ack) => (
<MenuItem key={ack.key} value={ack.key}>
{ack.value}
</MenuItem>
))}
</TextField>
);
}
The problem here is all to do with some pretty poor coding on the part of the MUI folks, where on several components, they have magic strings and really are doing silly things.
Let's take a look at the state here:
const [age, setAge] = React.useState('3');
You can see that we are having to specify the VALUE as a string. Indeed the data type that the Select control takes is a string | undefined. So the fact we are having to use a number value as a string is the source of confusion.
So how does that work?
It is all to do with the MenuItem component. Let's take a look:
<MenuItem value={1}>First Choice</MenuItem>
<MenuItem value={2}>Second Choice</MenuItem>
<MenuItem value={3}>Third Choice</MenuItem>
You can see that we are indeed having to specify the VALUE of the MenuItem as a number.
So in this case, specifying '3' as the State value, as a string, will select the Third Choice on load.
You can set the VALUE in the Select control as the state value.
Don't forget, when handling the onChange event, that you will need to convert the event.target.value to string.

Resources