I'm fetching data in index.tsx
which I later on pass to FormOne
just as following and I'm then able to use the data in FormOne using props.data
const [data, setData] = useState([]);
...
return (
...
<FormOne data={data} />
);
I want to replace "Pick a user" in FormOne
with a list of the users from props.data
. The idea is to select a user a query e.g. "What address does he have?", which leads to user's email address being printed right below the form, not sure how to do that either. How can I achieve that?
import {
Box,
Button,
FormControl,
Grid,
InputLabel,
MenuItem,
Select,
SelectChangeEvent,
TextField,
Typography,
} from '@mui/material';
import { useState } from 'react';
const FormOne = (props: any) => {
const [user, setUser] = useState('');
const [query, setQuery] = useState('');
const handleChange = (event: SelectChangeEvent) => {
setUser(event.target.value);
setQuery(event.target.value);
};
return (
<Box component="form" noValidate autoComplete="off">
<Typography component="h1" variant="h4" align="center">
GUI #1
</Typography>
<Grid container spacing={2}>
<Grid item xs={12}>
<FormControl variant="outlined" fullWidth>
<InputLabel id="demo-simple-select-label">Pick a user</InputLabel>
<Select
labelId="demo-simple-select-label"
id="demo-simple-select"
value={user}
onChange={handleChange}
>
<MenuItem value={10}>User 1</MenuItem>
<MenuItem value={20}>User 2</MenuItem>
<MenuItem value={30}>User 3</MenuItem>
</Select>
</FormControl>
</Grid>
<Grid item xs={12}>
<FormControl variant="outlined" fullWidth>
<InputLabel id="demo-simple-select-label">Query</InputLabel>
<Select
labelId="demo-simple-select-label"
id="demo-simple-select"
value={query}
onChange={handleChange}
>
<MenuItem value={10}>What email does he use?</MenuItem>
<MenuItem value={20}>What address does he have?</MenuItem>
</Select>
</FormControl>
</Grid>
<Grid item xs={12}>
<Button variant="contained">Submit</Button>
</Grid>
</Grid>
</Box>
);
};
export default FormOne;
CodeSandbox
CodePudding user response:
It seems to me like you want to dynamically render MenuItem components, in order to archive that you should replace your hardcoded
<MenuItem value={10}>User 1</MenuItem>
<MenuItem value={20}>User 2</MenuItem>
<MenuItem value={30}>User 3</MenuItem>
with something like this:
{props.data.map((item, index) => {
return <MenuItem key={index} value={item}>{item}</MenuItem>
})}
You can read more about Lists and Keys rendering here: https://reactjs.org/docs/lists-and-keys.html
In order to print user, since you are changing user on select change, after proper rendering MenuItems you should have that information inside user object and you should be able to render it like this.
{ user && <p>{user}</p> }
If you still need help, you need to add how data object looks like, in order for me to help you.
CodePudding user response:
import {
Box,
Button,
FormControl,
Grid,
InputLabel,
MenuItem,
Select,
SelectChangeEvent,
Typography,
} from '@mui/material';
import { useState } from 'react';
const FormOne = (props : any) => {
// for readablity and understanding I changed state names
const [selectedUser, setSelectedUser] = useState<any>();
const [selectedQuery, setSelectedQuery] = useState<any>();
// both handle change functions must be seperate
const handleQueryChange = (event: SelectChangeEvent) => {
setSelectedQuery(event.target.value);
};
const handleUserChange = (event : SelectChangeEvent) => {
// since select menu item accepts string number or string[] values we put id as the value but in state we can filter the user out like this
const selectedUser = props.data.filter((user:any)=>user.id === event.target.value);
setSelectedUser(selectedUser);
}
return (
<Box component="form" noValidate autoComplete="off">
<Typography component="h1" variant="h4" align="center">
GUI #1
</Typography>
<Grid container spacing={2}>
<Grid item xs={12}>
<FormControl variant="outlined" fullWidth>
<InputLabel id="demo-simple-select-label">Pick a user</InputLabel>
<Select
labelId="demo-simple-select-label"
id="demo-simple-select"
value={selectedUser}
onChange={handleUserChange}
>
{/* you can map users using javascript map function */}
{
props.data.map((user : any)=>(
<MenuItem value={user.id}>{user.name}</MenuItem>
))
}
</Select>
</FormControl>
</Grid>
<Grid item xs={12}>
<FormControl variant="outlined" fullWidth>
<InputLabel id="demo-simple-select-label">Query</InputLabel>
<Select
labelId="demo-simple-select-label"
id="demo-simple-select"
value={selectedQuery}
onChange={handleQueryChange}
>
{/* gave some values for the query items */}
<MenuItem value={1}>What email does he use?</MenuItem>
<MenuItem value={2}>What address does he have?</MenuItem>
</Select>
</FormControl>
</Grid>
<Grid item xs={12}>
<Button variant="contained">Submit</Button>
</Grid>
</Grid>
</Box>
);
};
export default FormOne;
I have changed state names to selectedUser
and selectedQuery
for readability.
For showing data on change of query you should do something like this wherever and however you want to show the data.
{selectedQuery === 1 && selectedUser &&(
<p>user email : {selectedUser?.email}</p>
) }
{selectedQuery === 2 && selectedUser &&(
<p>user address : {selectedUser?.address.street}
{selectedUser?.address.suite} {selectedUser?.address.city}</p>
) }
For working with typescript better you can add proper types
interface User{
id: number;
name: string;
email: string; // and so on
}
Similarly, you can add types to your states :
const [selectedUser, setSelectedUser] = useState<User>();
const [selectedQuery, setSelectedQuery] = useState<number>(1);
And in many more places where types are needed. I could help you more if you can provide more information.