nop
nop

Reputation: 6341

Using props data for a select field

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

Upvotes: 1

Views: 738

Answers (2)

Omama Zainab
Omama Zainab

Reputation: 880

import {
  Box,
  Button,
  FormControl,
  Grid,
  InputLabel,
  MenuItem,
  Select,
  SelectChangeEvent,
  Typography,
} from '@mui/material';
import { useState, useEffect } from 'react';

interface User {
  id: number;
  name: string;
  username: string;
  email: string;
  address: {
    street: string;
    suite: string;
    city: string;
    zipcode: string;
    geo: {
      lat: string;
      lng: string;
    };
  };
  phone: string;
  website: string;
  company: {
    name: string;
    catchPhrase: string;
    bs: string;
  };
}

const FormOne = (props: any) => {
  const [selectedUser, setSelectedUser] = useState<User | null>(null);
  const [selectedQuery, setSelectedQuery] = useState<number>(1);

  // both handle change functions must be seperate
  const handleQueryChange = (event: SelectChangeEvent) => {
    setSelectedQuery(Number(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 user = props.data.find(
      (user: User) => user.id === Number(event.target.value)
    );
    setSelectedUser(user);
  };

  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="user-label">Pick a user</InputLabel>
            <Select
              labelId="user-label"
              id="user"
              value={selectedUser?.id?.toString()}
              onChange={handleUserChange}
            >
              {/*  you can map users using javascript map function */}
              {props.data.map((user: User) => {
                return (
                  <MenuItem key={user.id} value={user.id.toString()}>
                    {user.email}
                  </MenuItem>
                );
              })}
            </Select>
          </FormControl>
        </Grid>

        <Grid item xs={12}>
          <FormControl variant="outlined" fullWidth>
            <InputLabel id="query-label">Query</InputLabel>
            <Select
              labelId="query-label"
              id="query"
              value={selectedQuery.toString()}
              onChange={handleQueryChange}
            >
              <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 item xs={12}>
          {selectedUser && selectedQuery === 1 && (
            <p>user email : {`${selectedUser?.email}`}</p>
          )}
          {selectedUser && selectedQuery === 2 && (
            <p>
              user address : {selectedUser?.address?.street}
              {selectedUser?.address?.city}
            </p>
          )}
        </Grid>
      </Grid>
    </Box>
  );
};

export default FormOne;

So basically, you needed to map props in order to get menuItems rendered. And, in order to show user data, you have to show it like I have done in my code.

Upvotes: 1

Wings
Wings

Reputation: 582

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.

Upvotes: 1

Related Questions