Appending MenuItems to Material-UI Select Input in React - javascript

So I'm not great with react or even javascript, but what I'm trying to do is take this react element:
const selectItem = (
<Select defaultValue="" id="type-select" label="Type">
<MenuItem value="">
<em>None</em>
</MenuItem>
</Select>
)
and append both subheader items and MenuItems from this:
Object.keys(greatSet).forEach(o => {
let subHeader = React.createElement('ListSubHeader',{class:'grouped-stuff'},o)
selectItem.appendChild(subHeader)
greatSet[o].forEach(option => {
let menuItem = React.createElement('MenuItem',{value: option.id}, option.name)
selectItem.appendChild(menuItem)
})
})
greatSet an object with key: array of objects, if that isn't clear.
What I want is similar to this:
<Select defaultValue="" id="grouped-select">
<MenuItem value="">
<em>None</em>
</MenuItem>
<ListSubheader>Category 1</ListSubheader>
<MenuItem value={1}>Option 1</MenuItem>
<MenuItem value={2}>Option 2</MenuItem>
<ListSubheader>Category 2</ListSubheader>
<MenuItem value={3}>Option 3</MenuItem>
<MenuItem value={4}>Option 4</MenuItem>
</Select>
What is the best way to do this?

Related

React+Material UI: How to change the font size of the Select component?

I'm developing a web app using React + Material UI. I would like to change the font size of the Select component. I'm having to use the MenuProps property, as the code snippet that follows. However, it's not working.
const MenuProps = {
PaperProps: {
sx: {
'& .MuiMenuItem-root': {
fontSize: 10,
},
},
style: {
fontSize: 10,
},
},
};
const MultipleSelectTags = () => {
const [tagFilter, setTagFilter] = useState([]);
const handleChange = (event) => {
const {
target: { value },
} = event;
setTagFilter(
typeof value === 'string' ? value.split(',') : value,
);
};
return (
<div>
<FormControl sx={{ m: 1, width: 200 }} size="small">
<InputLabel>Tag</InputLabel>
<Select
multiple
value={tagFilter}
onChange={handleChange}
input={<OutlinedInput label="Tag" />}
renderValue={(selected) => selected.join(', ')}
MenuProps={MenuProps}
>
{names.map((name) => (
<MenuItem key={name} value={name}>
<Checkbox checked={tagFilter.indexOf(name) > -1} />
<ListItemText primary={name} />
</MenuItem>
))}
</Select>
</FormControl>
</div>
);
}
Can somebody help me?
You can just add the font size prop directly to the Input:
<Select
multiple
value={tagFilter}
onChange={handleChange}
input={<OutlinedInput sx={{fontSize: '2rem'}} label="Tag" />}
renderValue={(selected) => selected.join(', ')}
>
{names.map((name) => (
<MenuItem key={name} value={name}>
<Checkbox checked={tagFilter.indexOf(name) > -1} />
<ListItemText primary={name} />
</MenuItem>
))}
</Select>
Here is a solution:
<Select
multiple
value={tagFilter}
onChange={handleChange}
input={<OutlinedInput label="Tag" />}
renderValue={(selected) => selected.join(', ')}
id="my-simple-select"
sx={{
'& #my-simple-select': {
fontSize: '2rem',
}
}}
>
{names.map((name) => (
<MenuItem key={name} value={name}>
<Checkbox checked={tagFilter.indexOf(name) > -1} />
<ListItemText primary={name} />
</MenuItem>
))}
</Select>
Also, if you want to apply it on the class level: '& .MuiSelect-select'
This is how I did it
<Select fullWidth
labelId="stateIdlabel"
id="stateId"
name="stateId" value={values.stateId}
label="label"
sx={{fontSize:'large'}}>
<MenuItem sx={{fontSize:'large'}} value={1}>OK</MenuItem>
<MenuItem sx={{fontSize:'large'}} value={2}>NOT</MenuItem>
</Select>

React Material-ui Select

After i implemented my application, i wanted to style it with Material UI.
When changing from html to Material i started recieving a warning when clicking select item:
index.js:1 Warning: findDOMNode is deprecated in StrictMode. findDOMNode was passed an instance of Transition which is inside StrictMode. Instead, add a ref directly to the element you want to reference.
Initial code:
<label htmlFor="newRole">Role</label>
<select
name="newRole"
id="newRole"
value={newUser.newRole}
onChange={handleChangeNew}
>
<option value="0">Student</option>
<option value="2">Professor</option>
<option value="3">Secretary</option>
</select>
Material UI code:
<InputLabel shrink id="role-lbl"> Role </InputLabel>
<Select
labelId="role-lbl"
name="newRole"
id="newRole"
value={newUser.newRole}
onChange={handleChangeNew}
// displayEmpty
variant="filled"
>
<MenuItem value="0">Student</MenuItem>
<MenuItem value="2">Professor</MenuItem>
<MenuItem value="3">Secretary</MenuItem>
</Select>
That is a little bit strange but I can not reproduce your warning. But as I faced it several times I can give you two advices how to fix it.
(not recommend) Just remove <React.StrictMode> wrapper on your <App />
useRefs. The idea might look like this:
import {InputLabel, MenuItem, Select} from "#material-ui/core";
import {useRef} from "react";
export default function Example3() {
const nodeRef = useRef(null);
function handleChangeNew(){
console.log('changed');
}
return(
<>
<InputLabel shrink id="role-lbl"> Role </InputLabel>
<Select
noderef={nodeRef}
labelId="role-lbl"
id="newRole"
value={newUser.newRole}
onChange={handleChangeNew}
// displayEmpty
variant="filled"
>
<MenuItem value="0" ref={nodeRef}>Student</MenuItem>
<MenuItem value="1" ref={nodeRef}>Professor</MenuItem>
<MenuItem value="2" ref={nodeRef}>Secretary</MenuItem>
</Select>
</>
)
}

click the text box text a popup menu should open with text box

when I click the text box text a popup menu should open with text box.
similarly when I click a filter icon in the right side corner a menu should open with list of checkboxes.
but right now whats happening is both the menus are opening when I click at both the places.
only one menu should open from one location.
I debugged by putting consoles. the problem is with the below methods
`const handleClick = event => {
setAnchorEl(event.currentTarget);
};
const handleClickFilter = event => {
setAnchorEl(event.currentTarget);
};`
can you tell me how to fix it.
providing my code snippet and sandbox below.
https://codesandbox.io/s/material-demo-kpt5i
const handleClick = event => {
setAnchorEl(event.currentTarget);
};
const handleClickFilter = event => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
const handleCloseFilter = () => {
setAnchorEl(null);
};
<Typography variant="h6" id="tableTitle" onClick={handleClickFilter}>
text box
<Menu
id="simple-menu"
anchorEl={anchorEl}
keepMounted
open={Boolean(anchorEl)}
onClose={handleCloseFilter}
>
<MenuItem onClick={handleCloseFilter}>
<form
className={classes.container}
noValidate
autoComplete="off"
>
<TextField
id="standard-name"
label="Name"
className={classes.textField}
// value={values.name}
// onChange={handleChange('name')}
margin="normal"
/>
</form>
</MenuItem>
</Menu>
</Typography>
<Tooltip title="Filter list">
<IconButton aria-label="filter list">
<FilterListIcon onClick={handleClick} />
<Menu
id="simple-menu"
anchorEl={anchorEl}
keepMounted
open={Boolean(anchorEl)}
onClose={handleClose}
>
<MenuItem onClick={handleClose}>
<Checkbox
onChange={handleColumnHide}
inputProps={{ "aria-label": "select all desserts" }}
value="name"
/>
Dessert
</MenuItem>
<MenuItem onClick={handleClose}>
<Checkbox
onChange={handleColumnHide}
inputProps={{ "aria-label": "select all desserts" }}
value="calories"
/>
Calories
</MenuItem>
<MenuItem onClick={handleClose}>
<Checkbox
onChange={handleColumnHide}
inputProps={{ "aria-label": "select all desserts" }}
/>
Fat
</MenuItem>
Alright, you had a couple issues on your code that was preventing this from working properly.
The idea of the 'anchor' element it's that the menu will attach to that DOM object and render right next to it; this is all handled for you by Material and it works like a charm but the thing it's that you need to have this anchors properly set.
First, you need a way to differenciate an anchor element for each menu you want to display (which in your case, it's two).
For this case to work, I used a 'type' prop inside of your anchor state object and another prop called 'target' which is the one that will store the 'event.currentTarget'. Something like this: { type: 'icon', target: event.currentTarget }
Then, you need to have each anchor element (which can be a button, an icon, a label, H1 or whatever you want) separated from the Menu component itself; if you do otherwise, then the Menu will never disappear and it can only be closed using TAB or refreshing. Something like this:
<Typography variant="h6" id="tableTitle">
<span onClick={handleClickFilter}>NOTICE THIS LABEL HAS THE MENU TRIGGER FUNCTION</span>
<Menu
id="simple-menu"
anchorEl={anchorEl && anchorEl.type === 'textbox' && anchorEl.target}
open={Boolean(anchorEl && anchorEl.type === 'textbox')}
onClose={handleClose}
>
<MenuItem>
<form
autoComplete="off"
>
<TextField
label="Name"
margin="normal"
/>
</form>
</MenuItem>
</Menu>
</Typography>
Then, finally you need the anchor handler functions, which at this point it's handled by a hook and it's storing with the same variable name except it's modifying the 'type' prop I mentioned before.
const handleClick = event => {
setAnchorEl({ type: 'textbox', target: event.currentTarget })
}
const handleClose = () => {
setAnchorEl(null)
}
This should do the work successfully.
Anyway, I modified your codepen code and updated it right here.
Hope this helps!

How to add disable option or default option in select box?

I am using react material in react with select component.I want to add first disable option something like “please select item”
Implemented in html like this
<select name="tagging">
<option selected disabled>I'm working</option>
<option value="Option B">Option B</option>
<option value="Option C">Option C</option>
</select>
How I will achieve this using material + react
here is my code
https://codesandbox.io/s/6836mkjx3
<FormControl className={classes.formControl}>
<InputLabel htmlFor="searchCriteria">SEARCH CRITERIA *</InputLabel>
<Select
value={searchCriteria}
onChange={event => handleInput(event, "searchCriteria")}
input={<Input name="searchCriteria" id="searchCriteria" />}
>
<MenuItem value={10}>Ten</MenuItem>
<MenuItem value={20}>Twenty</MenuItem>
<MenuItem value={30}>Thirty</MenuItem>
</Select>
<FormHelperText>Some important helper text</FormHelperText>
</FormControl>
here is select example in material
https://material-ui.com/demos/selects/
https://material-ui.com/demos/selects/#selects
This is what you are looking for
example is given in material ui documentation
You can implement it with
<MenuItem value="">
<em>None</em>
</MenuItem>
for standard material select and with <option value="" /> if you are using "native" material select.
Additionaly you can add disabled prop.
Codesandbox example forked from material-ui docs
use value="" for first option in material select.
<MenuItem selected disabled value="">
<em>None</em>
</MenuItem>
You need a label
import: import InputLabel from '#mui/material/InputLabel';
Component: <InputLabel id="demo-simple-select-disabled-label">Select one</InputLabel>

How to make a 'Select' component as required in Material UI (React JS)

I want to display like an error with red color unless there is a selected option.
Is there any way to do it.
For setting a required Select field with Material UI, you can do:
class SimpleSelect extends React.PureComponent {
state = {
selected: null,
hasError: false
}
handleChange(value) {
this.setState({ selected: value });
}
handleClick() {
this.setState(state => ({ hasError: !state.selected }));
}
render() {
const { classes } = this.props;
const { selected, hasError } = this.state;
return (
<form className={classes.root} autoComplete="off">
<FormControl className={classes.formControl} error={hasError}>
<InputLabel htmlFor="name">
Name
</InputLabel>
<Select
name="name"
value={selected}
onChange={event => this.handleChange(event.target.value)}
input={<Input id="name" />}
>
<MenuItem value="hai">Hai</MenuItem>
<MenuItem value="olivier">Olivier</MenuItem>
<MenuItem value="kevin">Kevin</MenuItem>
</Select>
{hasError && <FormHelperText>This is required!</FormHelperText>}
</FormControl>
<button type="button" onClick={() => this.handleClick()}>
Submit
</button>
</form>
);
}
}
Working Demo on CodeSandBox
Material UI has other types of Select(native) also where you can just use plain HTML required attribute to mark the element as required.
<FormControl className={classes.formControl} required>
<InputLabel htmlFor="name">Name</InputLabel>
<Select
native
required
value={this.state.name}
onChange={this.handleChange}
inputProps={{
name: 'name',
id: 'name'
}}
>
<option value="" />
<option value={"lala"}>lala</option>
<option value={"lolo"}>lolo</option>
</Select>
</FormControl>
P.S. https://material-ui.com/demos/selects/#native-select
The required prop only works when you wrap your elements inside a <form> element, and you used the submit event to submit the form.
this is not related to react, this is pure HTML.
In MUI v5 (2022), it works like this:
const handleSubmit = (e)=>{
e.preventDefault()
// ...
}
return (
<form onSubmit={handleSubmit}>
<Select required value={val} onChange={handleChange} required>
<MenuItem value="yes">Yes</MenuItem>
<MenuItem value="no">No</MenuItem>
</Select>
<Button type="submit">Submit</Button>
</form>
)
As you can see, it works the same way you think it should work, so what your code should probably be similar to this.
But the required prop only works when you wrap your elements inside a element, and you used the submit event to submit the form.
And if you're using <FormControl>, but the required prop on both elements:
<FormControl required>
<Select required>
// ...
</FormControl>

Categories

Resources