Show Material UI Select (Drop Down) conditionally based on option chosen - reactjs

Suppose we have the code :
import React from "react";
import { makeStyles } from "#material-ui/core/styles";
import InputLabel from "#material-ui/core/InputLabel";
import Input from "#material-ui/core/Input";
import MenuItem from "#material-ui/core/MenuItem";
import FormControl from "#material-ui/core/FormControl";
import Select from "#material-ui/core/Select";
const useStyles = makeStyles(theme => ({
formControl: {
margin: theme.spacing(1),
minWidth: 120
}
}));
function SuperForm() {
const classes = useStyles();
return (
<div>
<div>
<FormControl className={classes.formControl}>
<InputLabel htmlFor="grouped-native-select">Choose Type</InputLabel>
<Select
native
defaultValue=""
input={<Input id="grouped-native-select" />}
>
<option value={1}>Week</option>
<option value={2}>Plan</option>
</Select>
</FormControl>
<FormControl className={classes.formControl}>
<InputLabel htmlFor="grouped-select">Number</InputLabel>
<Select defaultValue="" input={<Input id="grouped-select" />}>
<MenuItem value="">
<em>None</em>
</MenuItem>
<MenuItem value={1}>1</MenuItem>
<MenuItem value={2}>2</MenuItem>
<MenuItem value={3}>3</MenuItem>
<MenuItem value={4}>4</MenuItem>
<MenuItem value={5}>5</MenuItem>
<MenuItem value={6}>6</MenuItem>
<MenuItem value={7}>7</MenuItem>
<MenuItem value={8}>8</MenuItem>
</Select>
</FormControl>
</div>
</div>
);
}
export default SuperForm;
How can we show the second FormControl of Number only when the user chooses Week in the first FormControl ?
When he chooses Plan I want to render nothing.
Thanks

Have a useState in your Component and default it's value to 1:
const [typeValue, setTypeValue] = React.useState("1");
And then when the user changes the select, handle it like this:
const handleChange = event => {
setTypeValue(event.target.value);
};
Finally, have a ternary in your return of the Component:
{typeValue === "1" ? (
<FormControl className={classes.formControl}>
<InputLabel htmlFor="grouped-select">Number</InputLabel>
<Select defaultValue="" input={<Input id="grouped-select" />}>
<MenuItem value="">
<em>None</em>
</MenuItem>
<MenuItem value={1}>1</MenuItem>
<MenuItem value={2}>2</MenuItem>
<MenuItem value={3}>3</MenuItem>
<MenuItem value={4}>4</MenuItem>
<MenuItem value={5}>5</MenuItem>
<MenuItem value={6}>6</MenuItem>
<MenuItem value={7}>7</MenuItem>
<MenuItem value={8}>8</MenuItem>
</Select>
</FormControl>
) : null}
Here's a Working Sample Demo for your ref.

We can achieve this using state:
import React, { useState } from "react";
import { makeStyles } from "#material-ui/core/styles";
import InputLabel from "#material-ui/core/InputLabel";
import Input from "#material-ui/core/Input";
import MenuItem from "#material-ui/core/MenuItem";
import FormControl from "#material-ui/core/FormControl";
import Select from "#material-ui/core/Select";
const useStyles = makeStyles(theme => ({
formControl: {
margin: theme.spacing(1),
minWidth: 120
}
}));
function SuperForm() {
const [selectedValue, setSelectedValue] = useState("");
const classes = useStyles();
return (
<div>
<div>
<FormControl className={classes.formControl}>
<InputLabel htmlFor="grouped-native-select">Choose Type</InputLabel>
<Select
native
value={selectedValue}
onChange={event => setSelectedValue(event.target.value)}
defaultValue=""
input={<Input id="grouped-native-select" />}
>
<option value={1}>Week</option>
<option value={2}>Plan</option>
</Select>
</FormControl>
{selectedValue === "1" && (
<FormControl className={classes.formControl}>
<InputLabel htmlFor="grouped-select">Number</InputLabel>
<Select defaultValue="" input={<Input id="grouped-select" />}>
<MenuItem value="">
<em>None</em>
</MenuItem>
<MenuItem value={1}>1</MenuItem>
<MenuItem value={2}>2</MenuItem>
<MenuItem value={3}>3</MenuItem>
<MenuItem value={4}>4</MenuItem>
<MenuItem value={5}>5</MenuItem>
<MenuItem value={6}>6</MenuItem>
<MenuItem value={7}>7</MenuItem>
<MenuItem value={8}>8</MenuItem>
</Select>
</FormControl>
)}
</div>
</div>
);
}
export default SuperForm;

Related

MUI Select Component Rendering Weirdly

I have a custom component that consist of 3 Select components. However Select's are not rendering correctly. Their labels are seen next to the Select components instead of inside/on top of the border. See this See this also It should have looked like this
I tested this component on a code sandbox and it was working but not sure why it is not working in my project. I have #mui/material: 5.11.9 and react: 18.2.0
My component:
import React from 'react';
import {
Button,
Menu,
MenuItem,
Select,
FormControl,
InputLabel,
} from '#mui/material';
const FilterComponent = () => {
const [open, setOpen] = React.useState(false);
const [modifiedValue, setModifiedValue] = React.useState('');
const [fileValue, setFileValue] = React.useState('');
const [numberValue, setNumberValue] = React.useState('');
const handleOpen = () => {
setOpen(true);
};
const handleClose = () => {
setOpen(false);
};
const handleModifiedChange = (event) => {
setModifiedValue(event.target.value);
};
const handleFileChange = (event) => {
setFileValue(event.target.value);
};
const handleNumberChange = (event) => {
setNumberValue(event.target.value);
};
return (
<div>
<Button variant='contained' onClick={handleOpen}>
Filter
</Button>
<Menu
id='filter-menu'
anchorEl={open}
open={Boolean(open)}
onClose={handleClose}
>
<MenuItem>
<FormControl
variant='standard'
sx={{ m: 1, minWidth: 200 }}
>
<InputLabel>Modified</InputLabel>
<Select
value={modifiedValue}
onChange={handleModifiedChange}
>
<MenuItem value='Modified'>Modified</MenuItem>
<MenuItem value='Removed'>Removed</MenuItem>
<MenuItem value='Affected'>Affected</MenuItem>
</Select>
</FormControl>
</MenuItem>
<MenuItem>
<FormControl
variant='standard'
sx={{ m: 1, minWidth: 200 }}
>
<InputLabel>File</InputLabel>
<Select value={fileValue} onChange={handleFileChange}>
<MenuItem value='a.java'>a.java</MenuItem>
<MenuItem value='b.java'>b.java</MenuItem>
</Select>
</FormControl>
</MenuItem>
<MenuItem>
<FormControl
variant='standard'
sx={{ m: 1, minWidth: 200 }}
>
<InputLabel>Number</InputLabel>
<Select
value={numberValue}
onChange={handleNumberChange}
>
<MenuItem value={1}>1</MenuItem>
<MenuItem value={2}>2</MenuItem>
<MenuItem value={3}>3</MenuItem>
</Select>
</FormControl>
</MenuItem>
</Menu>
</div>
);
};
export default FilterComponent;

click on MUI's select in bootstrap dropdown makes it disappear

As the title said, I have a material UI's select in a bootstrap dropdown. When I click on the select, the dropdown closes, and the popover than appear is placed in a bad place.
Assuming that the popover should be created inside the dropdown for it not to happen, I tried to make it this way, using the anchorEl.
The console tells me "Popover.js:162 MUI: The anchorEl prop provided to the component is invalid.
The anchor element should be part of the document layout.
Make sure the element is present in the document or that it's not display none."
And it doesn't fix the issue. I'm quite lost, any idea? As a detail, I made a test using Button + Popover instead of the select, and it works.
Code:
import "./styles.css";
import React, { useRef, useState } from "react";
import Select from "#mui/material/Select";
import FormControl from "#mui/material/FormControl";
import MenuItem from "#mui/material/MenuItem";
function MySelect() {
const ref = useRef();
const [value, setValue] = useState("null");
const [anchor, setAnchor] = useState(null);
const handleChange = () => {};
const onOpen = (e) => {
setAnchor(e.currentTarget);
};
return (
<>
<div ref={ref}>
<FormControl fullWidth>
<Select
value={value}
onOpen={onOpen}
onChange={handleChange}
MenuProps={{ anchorEl: anchor, anchorReference: "anchorEl" }}
>
<MenuItem value="null">Hey</MenuItem>
<MenuItem value="hello">Hello</MenuItem>
<MenuItem value="hello2">Hello</MenuItem>
<MenuItem value="hello3">Hello</MenuItem>
<MenuItem value="hello4">Hello</MenuItem>
<MenuItem value="hello5">Hello</MenuItem>
<MenuItem value="hello6">Hello</MenuItem>
<MenuItem value="hello7">Hello</MenuItem>
<MenuItem value="hello8">Hello</MenuItem>
<MenuItem value="hello9">Hello</MenuItem>
<MenuItem value="hello10">Hello</MenuItem>
<MenuItem value="hello11">Hello</MenuItem>
<MenuItem value="hello12">Hello</MenuItem>
<MenuItem value="hello13">Hello</MenuItem>
<MenuItem value="hello14">Hello</MenuItem>
<MenuItem value="hello15">Hello</MenuItem>
<MenuItem value="hello16">Hello</MenuItem>
<MenuItem value="hello17">Hello</MenuItem>
<MenuItem value="hello18">Hello</MenuItem>
<MenuItem value="hello19">Hello</MenuItem>
<MenuItem value="hello20">Hello</MenuItem>
<MenuItem value="hello21">Hello</MenuItem>
</Select>
</FormControl>
</div>
</>
);
}
export default function App() {
return (
<div className="App" style={{ width: "400px" }}>
<div
id="my-dropdown"
className="dropdown"
style={{ marginLeft: "200px" }}
>
<a
id="my-btn"
href="#"
data-bs-toggle="dropdown"
data-bs-auto-close="outside"
aria-expanded="false"
>
Filter
</a>
<div
className="dropdown-menu dropdown-menu-sm-end"
aria-labelledby="my-btn"
>
<div>stuff to fill a bit</div>
<MySelect />
</div>
</div>
</div>
);
}
Link to try : https://codesandbox.io/s/lucid-babbage-5gfcqo?file=/src/App.js

I want the answer to a question to appear on the screen for confirmation

We are using Material-UI in React to create a web form.
In components / Content.js, case 3: I want to create a confirmation screen that displays the answer to the question below.
I've done a lot of research, but I'm stuck in a situation where I don't know how to implement it.
Can anyone give me some advice?
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
reportWebVitals();
App.js
import "./App.css";
import { Grid } from "#mui/material";
import Header from "./components/Header";
import Content from "./components/Content";
function App() {
return (
<Grid container direction="column">
<Header />
<div style={{ padding: 30 }}>
<Content />
</div>
</Grid>
);
}
export default App;
src / components / contents.js
import React from "react";
import { Grid } from "#mui/material";
import Stepper from "#mui/material/Stepper";
import Step from "#mui/material/Step";
import StepLabel from "#mui/material/StepLabel";
import Button from "#mui/material/Button";
import Typography from "#mui/material/Typography";
import Radio from "#mui/material/Radio";
import RadioGroup from "#mui/material/RadioGroup";
import FormControlLabel from "#mui/material/FormControlLabel";
import FormControl from "#mui/material/FormControl";
import FormLabel from "#mui/material/FormLabel";
import Tooltip from "#mui/material/Tooltip";
import TextField from "#mui/material/TextField";
import InputLabel from "#mui/material/InputLabel";
import Select from "#mui/material/Select";
function getSteps() {
return ["お客様の情報を入力してください", "以下にお答えください", "ご相談ください", "以下の内容をご確認ください"];
}
function getStepContent(stepIndex) {
switch (stepIndex) {
case 0:
return (
<>
{/* <DatePicker views={["year"]} label="Year only" value={selectedDate} onChange={handleDateChange} /> */}
<div>
<FormControl component="fieldset">
<FormLabel component="legend">- 性別 -</FormLabel>
<RadioGroup row aria-label="gender" name="row-radio-buttons-group">
<FormControlLabel value="male" control={<Radio />} label="男性" />
<FormControlLabel value="female" control={<Radio />} label="女性" />
</RadioGroup>
</FormControl>
</div>
<div>
<FormLabel component="legend">- 生年月日 -</FormLabel>
<FormControl sx={{ m: 1, minWidth: 120 }}>
<InputLabel htmlFor="grouped-native-select">year</InputLabel>
<Select native defaultValue="" id="grouped-native-select" label="Grouping">
<option aria-label="None" value="" />
<optgroup label="year">
{Array.from(Array(2020), (_, num) => (
<option key={num} value={num + 1}>
{num + 1990}
</option>
))}
</optgroup>
</Select>
</FormControl>
<FormControl sx={{ m: 1, minWidth: 120 }}>
<InputLabel htmlFor="grouped-native-select">month</InputLabel>
<Select native defaultValue="" id="grouped-native-select" label="Grouping">
<option aria-label="None" value="" />
<optgroup label="month">
{Array.from(Array(12), (_, num) => (
<option key={num} value={num + 1}>
{num + 1}
</option>
))}
</optgroup>
</Select>
</FormControl>
<FormControl sx={{ m: 1, minWidth: 120 }}>
<InputLabel htmlFor="grouped-native-select">day</InputLabel>
<Select native defaultValue="" id="grouped-native-select" label="Grouping">
<option aria-label="None" value="" />
<optgroup label="day">
{Array.from(Array(31), (_, num) => (
<option key={num} value={num + 1}>
{num + 1}
</option>
))}
</optgroup>
</Select>
</FormControl>
</div>
</>
);
case 1:
return (
<div>
<FormControl component="fieldset">
<FormLabel component="legend">現在、生命保険に加入されていますか?</FormLabel>
<RadioGroup row aria-label="gender" name="row-radio-buttons-group">
<FormControlLabel value="yes" control={<Radio />} label="はい" />
<FormControlLabel value="no" control={<Radio />} label="いいえ" />
</RadioGroup>
<FormLabel component="legend">
現在、入院中ですか。また、3ヶ月以内に医師の診察・検査の結果、入院・手術をすすめられたことがありますか?
</FormLabel>
<RadioGroup row aria-label="gender" name="row-radio-buttons-group">
<FormControlLabel value="yes" control={<Radio />} label="はい" />
<FormControlLabel value="no" control={<Radio />} label="いいえ" />
</RadioGroup>
<FormLabel component="legend">
過去、5年以内に病気やケガで手術を受けたことまたは継続して7日以上の入院をしたことはありますか?
</FormLabel>
<RadioGroup row aria-label="gender" name="row-radio-buttons-group">
<FormControlLabel value="yes" control={<Radio />} label="はい" />
<FormControlLabel value="no" control={<Radio />} label="いいえ" />
</RadioGroup>
</FormControl>
</div>
);
case 2:
return (
<Grid container>
<Grid sm={2} />
<Grid lg={8} sm={8} spacing={10}>
<Tooltip title="ご相談内容を記入することができます" placement="top-start" arrow>
<TextField
label="ご相談内容"
fullWidth
margin="normal"
rows={4}
multiline
variant="outlined"
placeholder="その他ご要望等あれば、ご記入ください"
/>
</Tooltip>
</Grid>
</Grid>
);
case 3:
return (
<div>
<FormControl component="fieldset">
<FormLabel component="legend">- 性別 -</FormLabel>
<FormLabel component="legend">- 生年月日 -</FormLabel>
<FormLabel component="legend">現在、生命保険に加入されていますか?</FormLabel>
<FormLabel component="legend">
現在、入院中ですか。また、3ヶ月以内に医師の診察・検査の結果、入院・手術をすすめられたことがありますか?
</FormLabel>
<FormLabel component="legend">
過去、5年以内に病気やケガで手術を受けたことまたは継続して7日以上の入院をしたことはありますか?
</FormLabel>
<FormLabel component="legend">ご相談内容</FormLabel>
</FormControl>
</div>
);
default:
return "Unknown stepIndex";
}
}
function Content() {
const [activeStep, setActiveStep] = React.useState(0);
const steps = getSteps();
const handleNext = () => {
setActiveStep((prevActiveStep) => prevActiveStep + 1);
};
const handleBack = () => {
setActiveStep((prevActiveStep) => prevActiveStep - 1);
};
const handleReset = () => {
setActiveStep(0);
};
return (
<Grid container>
<Grid sm={2} />
<Grid lg={8} sm={8} spacing={10}>
<Stepper activeStep={activeStep} alternativeLabel>
{steps.map((label) => (
<Step key={label}>
<StepLabel>{label}</StepLabel>
</Step>
))}
</Stepper>
{activeStep === steps.length ? (
<div>
<Typography>全ステップの表示を完了</Typography>
<Button onClick={handleReset}>リセット</Button>
</div>
) : (
<div>
<Typography>{getStepContent(activeStep)}</Typography>
<Button disabled={activeStep === 0} onClick={handleBack}>
戻る
</Button>
<Button variant="contained" color="primary" onClick={handleNext}>
{activeStep === steps.length - 1 ? "送信" : "次へ"}
</Button>
</div>
)}
</Grid>
</Grid>
);
}
export default Content;

Material ui list of select item need to be selected

i have created selected box..using functional component...i am getting list of items from the back end, i am looping that list and showing in the front end....now i need to be selected item need to show in the box what i have selected...could any one help on this...
Please see my example code in this link https://codesandbox.io/s/gallant-water-fnqiv
import React from "react";
import { makeStyles } from "#material-ui/core/styles";
import InputLabel from "#material-ui/core/InputLabel";
import MenuItem from "#material-ui/core/MenuItem";
import FormControl from "#material-ui/core/FormControl";
import Select from "#material-ui/core/Select";
const useStyles = makeStyles(theme => ({
formControl: {
margin: theme.spacing(1),
minWidth: 120
},
selectEmpty: {
marginTop: theme.spacing(2)
}
}));
const lists = ["Ten", "twenty", "Thirty", "Fourty", "Fifity", "Sixty"];
export default function SimpleSelect() {
const classes = useStyles();
const [age, setAge] = React.useState("");
const inputLabel = React.useRef(null);
const [labelWidth, setLabelWidth] = React.useState(0);
React.useEffect(() => {
setLabelWidth(inputLabel.current.offsetWidth);
}, []);
const handleChange = event => {
setAge(event.target.value);
};
return (
<div>
<FormControl variant="outlined" className={classes.formControl}>
<InputLabel ref={inputLabel} id="demo-simple-select-outlined-label">
Age
</InputLabel>
<Select
labelId="demo-simple-select-outlined-label"
id="demo-simple-select-outlined"
value={age}
onChange={handleChange}
labelWidth={labelWidth}
>
<MenuItem value={""}>
{lists.map(item => {
<li>{item.list}</li>;
})}
</MenuItem>
</Select>
</FormControl>
</div>
);
}
There is no property in the array named, item.list , so you need to use item alone which itself gives the value you want.
Also make sure <MenuItem value={item}> is inside the lists.map() method..
Include return statement of the MenuItemis inside ofthe lists.map() method which throws error in your codesandbox link
And hence,
Change:
<MenuItem value={""}>
{lists.map(item => {
<li>{item.list}</li>;
})}
</MenuItem>
To:
{lists.map(item => {
return (
<MenuItem value={item}>
<li>{item}</li>
</MenuItem>
);
})}
Forked Codesandbox
you can try this-
<div>
<FormControl variant="outlined" className={classes.formControl}>
<InputLabel ref={inputLabel} id="demo-simple-select-outlined-label">
Age
</InputLabel>
<Select
labelId="demo-simple-select-outlined-label"
id="demo-simple-select-outlined"
value={age}
onChange={handleChange}
labelWidth={labelWidth}
>
{lists.map(item => (
<MenuItem value={item}>{item}</MenuItem>
))}
</Select>
</FormControl>
</div>
https://codesandbox.io/s/material-ui-select-m8lgt
Updated code sandbox link
Your MenuItem was wrong.
{lists.map(item => (
<MenuItem value={item}>{item}</MenuItem>
))}

Select MenuItem doesn't show when JSX saved to state

Working from the demo here: https://material-ui.com/demos/selects/ and I'm receiving some weird results. Specifically, when I select an item from the drop-down menu, the this.props.value updates fine... but the MenuItem does not show up.
If I put the <FormControl> tag directly in render, it works fine. If I put in an a variable, then setState with that and insert that into the render... it does NOT work.
Example:
import React from 'react';
import PropTypes from 'prop-types';
import { withStyles } from '#material-ui/core/styles';
import InputLabel from '#material-ui/core/InputLabel';
import MenuItem from '#material-ui/core/MenuItem';
import FormControl from '#material-ui/core/FormControl';
import Select from '#material-ui/core/Select';
const styles = theme => ({
root: {
display: 'flex',
flexWrap: 'wrap',
},
formControl: {
margin: theme.spacing.unit,
minWidth: 120,
},
selectEmpty: {
marginTop: theme.spacing.unit * 2,
},
});
class Question extends React.Component {
state = {
age: '',
age2: '',
slct: ''
};
componentDidMount() {
const { classes } = this.props;
var mySelect =
<FormControl className={classes.formControl}>
<InputLabel htmlFor="age-simple">Age</InputLabel>
<Select
value={this.state.age}
onChange={this.handleChange}
inputProps={{
name: 'age',
id: 'age-simple',
}}
>
<MenuItem value="">
<em>None</em>
</MenuItem>
<MenuItem value={10}>Ten</MenuItem>
<MenuItem value={20}>Twenty</MenuItem>
<MenuItem value={30}>Thirty</MenuItem>
</Select>
</FormControl>
this.setState({ slct: mySelect });
}
handleChange = event => {
this.setState({ [event.target.name]: event.target.value });
};
render() {
const { classes } = this.props;
return (
<div>
{this.state.slct}
<p>Value:</p>{this.state.age}
<FormControl className={classes.formControl}>
<InputLabel htmlFor="age-simple2">Age</InputLabel>
<Select
value={this.state.age2}
onChange={this.handleChange}
inputProps={{
name: 'age2',
id: 'age-simple2',
}}
>
<MenuItem value="">
<em>None</em>
</MenuItem>
<MenuItem value={10}>Ten</MenuItem>
<MenuItem value={20}>Twenty</MenuItem>
<MenuItem value={30}>Thirty</MenuItem>
</Select>
</FormControl>
<p>Value:</p>{this.state.age2}
</div>
);
}
}
export default withStyles(styles)(Question);
You can see how the 'value' updates correctly for both based on which answer I select in the drop down... but visually, the MenuItem label never appears to show up for the one that's coming from state:
Help?
(fyi: these items are in a parents' <form>.)
it has to be a function or an Array for rendering. To make your code work, it should be:
state = {
slct: <FormControl>...</FormControl>
}
slctRenderer = () => this.state.slct;
render() {
return (
<div>
{this.slctRenderer()}
</div>
);
}
Using the information from #Jee Mok ... the idea that it might work as a function (even though other items don't seem to care) made me try the following changes to the initial code:
Added this function:
selectRenderer() {
const { classes } = this.props;
return (
<FormControl className={classes.formControl}>
<InputLabel htmlFor="age-simple">Age</InputLabel>
<Select
value={this.state.age}
onChange={this.handleChange}
inputProps={{
name: 'age',
id: 'age-simple',
}}
>
<MenuItem value="">
<em>None</em>
</MenuItem>
<MenuItem value={10}>Ten</MenuItem>
<MenuItem value={20}>Twenty</MenuItem>
<MenuItem value={30}>Thirty</MenuItem>
</Select>
</FormControl>
);
};
And then in the component's render function, I call it:
render() {
return (
<div>
{this.selectRenderer()}
<p>Value:</p>{this.state.age}
</div>
);
}
This works. (and thus I'll mark it answered in two days)
I am curious, however, WHY this particular chunk of JSX needs to be brought in as a function whereas other chunks of JSX do not. (specifically, a material-ui text field works just fine being assigned to state as I did in the OP) I'd like to be able to build out this question once (preferably as part of the componentDidMount lifecycle) and then pass the built-out question somehow to the render function. State seems to be the way to do that, but I can't with Select/MenuItems for some reason.

Resources