Home > Enterprise >  Using props data for a select field
Using props data for a select field

Time:03-28

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.

  • Related