HelloWorld1
HelloWorld1

Reputation: 14108

How to display Dialog in relation to many rows in the table

Goal:
Get data and display it in the dialog by using the button that is located in the column Button. In other words, you click one of the buttons and data will be displayed in the dialog.

Problem:
Today, I can only get the data by hard coding a single data but if you need to use the single dialog with different url, you probably need to code in a different approach. Please take account that you have for instance 100 row and you need to use a single <Form id={id} /> and not using 100 of <Form id={id} />.

I have difficult to create to make a single <Form id={id} /> in relation to many rows from the table.

Info:
*Please take account that you need to use the data from the table or you can hard code it.
*You use url 'https://jsonplaceholder.typicode.com/todos/x' but you use the number from the table as a input data in order to send it to the Form.tsx.
*My skill in react TS is beginner level in relation to hobby project.

Stackblitz:
https://stackblitz.com/edit/react-ts-dhacdg

App.tsx

import * as React from 'react';
import Button from '@mui/material/Button';
import Dialog, { DialogProps } from '@mui/material/Dialog';
import DialogActions from '@mui/material/DialogActions';
import DialogContent from '@mui/material/DialogContent';
import DialogContentText from '@mui/material/DialogContentText';
import DialogTitle from '@mui/material/DialogTitle';
import { Form } from './Form';

export default function ScrollDialog() {
  const [open, setOpen] = React.useState(false);
  const [scroll, setScroll] = React.useState<DialogProps['scroll']>('paper');
  const [id, setId] = React.useState(0);

  const handleClickOpen = (scrollType: DialogProps['scroll']) => () => {
    setOpen(true);
    setScroll(scrollType);
  };

  const handleClose = () => {
    setOpen(false);
  };

  const descriptionElementRef = React.useRef<HTMLElement>(null);
  React.useEffect(() => {
    if (open) {
      const { current: descriptionElement } = descriptionElementRef;
      if (descriptionElement !== null) {
        descriptionElement.focus();
      }
    }
  }, [open]);

  return (
    <div>
      <table border={0}>
        <thead>
          <tr>
            <th>Name</th>
            <th>Input Data</th>
            <th>Button</th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <td>a</td>
            <td>1</td>
            <td>
              <button>Get Data</button>
            </td>
          </tr>
          <tr>
            <td>b</td>
            <td>2</td>
            <td>
              <button>Get Data</button>
            </td>
          </tr>
          <tr>
            <td>c</td>
            <td>3</td>
            <td>
              <button>Get Data</button>
            </td>
          </tr>
        </tbody>
      </table>
      <Form id={id} />
    </div>
  );
}

Form.tsx

import React, { useState } from 'react';
import Button from '@mui/material/Button';
import Dialog, { DialogProps } from '@mui/material/Dialog';
import DialogActions from '@mui/material/DialogActions';
import DialogContent from '@mui/material/DialogContent';
import DialogContentText from '@mui/material/DialogContentText';
import DialogTitle from '@mui/material/DialogTitle';
import useMediaQuery from '@mui/material/useMediaQuery';
import { useTheme } from '@mui/material/styles';

export const Form = ({ id }: { id: number }) => {
  const [inputid, setInputid] = useState('');
  const [inputTitle, setInputTitle] = useState('');

  React.useEffect(() => {
    async function FetchData() {
      var data = await fetch(
        'https://jsonplaceholder.typicode.com/todos/1'
      ).then((res) => {
        return res.json();
      });
      setInputid(data.id);
      setInputTitle(data.title);
    }

    FetchData();
  }, [id]);

  const [open, setOpen] = React.useState(false);
  const theme = useTheme();
  const [scroll, setScroll] = React.useState<DialogProps['scroll']>('paper');
  const fullScreen = useMediaQuery(theme.breakpoints.down('md'));

  const handleClickOpen = () => () => {
    var scrollType: DialogProps['scroll'];
    scrollType = 'body';

    setOpen(true);
    setScroll(scrollType);
  };

  const handleClose = () => {
    setOpen(false);
  };

  const descriptionElementRef = React.useRef<HTMLElement>(null);
  React.useEffect(() => {
    if (open) {
      const { current: descriptionElement } = descriptionElementRef;
      if (descriptionElement !== null) {
        descriptionElement.focus();
      }
    }
  }, [open]);
  return (
    <div>
      <button onClick={handleClickOpen()}>Get Data</button>
      <Dialog
        fullScreen={fullScreen}
        open={open}
        scroll={scroll}
        aria-labelledby="scroll-dialog-title"
        aria-describedby="scroll-dialog-description"
      >
        <DialogTitle id="scroll-dialog-title">Subscribe</DialogTitle>
        <DialogContent dividers={scroll === 'paper'}>
          <DialogContentText
            id="scroll-dialog-description"
            ref={descriptionElementRef}
            tabIndex={-1}
          >
            {inputid}
            <br />
            {inputTitle}
          </DialogContentText>
        </DialogContent>
        <DialogActions>
          <Button onClick={handleClose}>Cancel</Button>
        </DialogActions>
      </Dialog>
    </div>
  );
};

Upvotes: 1

Views: 499

Answers (1)

Drew Reese
Drew Reese

Reputation: 202676

Use the open state of the parent App component to toggle the Form component opened/closed. Pass the id to the handleClickOpen handler to (a) set the current active id state and (b) open the Form component.

Example:

App

export default function App() {
  const [open, setOpen] = React.useState(false);
  const [scroll, setScroll] = React.useState<DialogProps["scroll"]>("paper");
  const [id, setId] = React.useState(0);

  const handleClickOpen = (id: number) => () => {
    const scrollType: DialogProps["scroll"] = "body";

    setOpen(true);
    setId(id);
    setScroll(scrollType);
  };

  const handleClose = () => {
    setOpen(false);
  };

  const descriptionElementRef = React.useRef<HTMLElement>(null);

  React.useEffect(() => {
    if (open) {
      const { current: descriptionElement } = descriptionElementRef;
      if (descriptionElement !== null) {
        descriptionElement.focus();
      }
    }
  }, [open]);

  return (
    <div className="App">
      <div>
        <table border={0}>
          <thead>
            <tr>
              <th>Name</th>
              <th>Input Data</th>
              <th>Button</th>
            </tr>
          </thead>
          <tbody>
            {[
              { name: "a", id: 1 },
              { name: "b", id: 2 },
              { name: "c", id: 3 }
            ].map(({ name, id }) => (
              <tr>
                <td>{name}</td>
                <td>{id}</td>
                <td>
                  <button onClick={handleClickOpen(id)}>Get Data</button>
                </td>
              </tr>
            ))}
          </tbody>
        </table>
        <Form id={id} open={open} onClose={handleClose} />
      </div>
    </div>
  );
}

Form - Declare the props interface to take also the open and onClose props. For the fetch use a template string to inject the passed id prop into the request URL.

interface FormProps {
  id: number;
  open: boolean;
  onClose: () => void;
}

export const Form = ({ id, open, onClose }: FormProps) => {
  const [inputid, setInputid] = useState("");
  const [inputTitle, setInputTitle] = useState("");

  React.useEffect(() => {
    async function FetchData() {
      try {
        const res = await fetch(
          `https://jsonplaceholder.typicode.com/todos/${id}`
        );
        const data = await res.json();
        setInputid(data.id);
        setInputTitle(data.title);
      } catch {
        // handle?
      }
    }

    FetchData();
  }, [id]);

  const theme = useTheme();
  const [scroll, setScroll] = React.useState<DialogProps['scroll']>('paper');
  const fullScreen = useMediaQuery(theme.breakpoints.down("md"));

  const handleClose = () => {
    onClose();
  };

  const descriptionElementRef = React.useRef<HTMLElement>(null);

  React.useEffect(() => {
    if (open) {
      const { current: descriptionElement } = descriptionElementRef;
      if (descriptionElement !== null) {
        descriptionElement.focus();
      }
    }
  }, [open]);

  return (
    <div>
      <Dialog
        fullScreen={fullScreen}
        open={open}
        scroll={scroll}
        aria-labelledby="scroll-dialog-title"
        aria-describedby="scroll-dialog-description"
      >
        <DialogTitle id="scroll-dialog-title">Subscribe</DialogTitle>
        <DialogContent dividers={scroll === "paper"}>
          <DialogContentText
            id="scroll-dialog-description"
            ref={descriptionElementRef}
            tabIndex={-1}
          >
            {inputid}
            <br />
            {inputTitle}
          </DialogContentText>
        </DialogContent>
        <DialogActions>
          <Button onClick={handleClose}>Cancel</Button>
        </DialogActions>
      </Dialog>
    </div>
  );
};

Edit how-to-display-dialog-in-relation-to-many-rows-in-the-table

Upvotes: 1

Related Questions