Search code examples
reactjsmui-datatable

Upload CSV file in Mui-Datatables


How to upload CSV file in Mui-Datatables and display in the table? I am new to Mui-Datatable


Solution

  • A way to upload CSV files to MUI Datatables is to use the npm package React-Papaparse.

    I have set up a Code Sandbox here as an example of how it could be set up.

    MockData.csv

    name,city,company,state
    Hansiain Babar,Richmond,Mybuzz,Virginia
    Carissa Lenormand,Pittsburgh,Yambee,Pennsylvania
    Weber Skeath,Young America,Mymm,Minnesota
    Ashton Pashan,Loretto,Brainsphere,Minnesota
    Willi Martignoni,Minneapolis,Realmix,Minnesota
    Aarika Philippart,Tacoma,Fadeo,Washington
    Crichton Worpole,Inglewood,Edgetag,California
    Marna Climer,Colorado Springs,Flashspan,Colorado
    Gilemette Arington,Amarillo,Trudeo,Texas
    Maryanne Gostage,Richmond,Skyba,Virginia
    

    CSVUploader.jsx

    This is essentially pulled from the React-Paparse Docs, but with the config={{headers: true}}:

    import React from "react";
    import { CSVReader } from "react-papaparse";
    
    const buttonRef = React.createRef();
    
    const CSVReader1 = (props) => {
      const { setCSVData } = props;
      const handleOpenDialog = (e) => {
        // Note that the ref is set async, so it might be null at some point
        if (buttonRef.current) {
          buttonRef.current.open(e);
        }
      };
    
      const handleOnFileLoad = (data) => {
        console.log("---------------------------");
        console.log(data);
        /* *** When the headers config option is set to 'true', it 
        returns an empty object as the last item in the array, 
        so we need to remove it: *** */
        data.pop();
        setCSVData(data);
        console.log("---------------------------");
      };
    
      const handleOnError = (err, file, inputElem, reason) => {
        console.log("---------------------------");
        console.log(err);
        console.log("---------------------------");
      };
    
      const handleOnRemoveFile = (data) => {
        console.log("---------------------------");
        console.log(data);
        console.log("---------------------------");
      };
    
      const handleRemoveFile = (e) => {
        // Note that the ref is set async, so it might be null at some point
        if (buttonRef.current) {
          buttonRef.current.removeFile(e);
        }
      };
    
      return (
        <>
          <h5>Basic Upload</h5>
          <CSVReader
            ref={buttonRef}
            onFileLoad={handleOnFileLoad}
            onError={handleOnError}
            noClick
            noDrag
            config={{ header: true }}
            onRemoveFile={handleOnRemoveFile}
          >
            {({ file }) => (
              <aside
                style={{
                  display: "flex",
                  flexDirection: "row",
                  marginBottom: 10
                }}
              >
                <button
                  type="button"
                  onClick={handleOpenDialog}
                  style={{
                    borderRadius: 0,
                    marginLeft: 0,
                    marginRight: 0,
                    width: "40%",
                    paddingLeft: 0,
                    paddingRight: 0
                  }}
                >
                  Browse file
                </button>
                <div
                  style={{
                    borderWidth: 1,
                    borderStyle: "solid",
                    borderColor: "#ccc",
                    height: 45,
                    lineHeight: 2.5,
                    marginTop: 5,
                    marginBottom: 5,
                    paddingLeft: 13,
                    paddingTop: 3,
                    width: "60%"
                  }}
                >
                  {file && file.name}
                </div>
                <button
                  style={{
                    borderRadius: 0,
                    marginLeft: 0,
                    marginRight: 0,
                    paddingLeft: 20,
                    paddingRight: 20
                  }}
                  onClick={handleRemoveFile}
                >
                  Remove
                </button>
              </aside>
            )}
          </CSVReader>
        </>
      );
    };
    
    export default CSVReader1;
    

    CustomToolbar.jsx

    Here, we have a customToolbar component, which is basically the same a the default toolbar but with an extra button we will add to upload the CSV file:

    import React, { useEffect, useState } from "react";
    import IconButton from "@material-ui/core/IconButton";
    import Tooltip from "@material-ui/core/Tooltip";
    import AddCircleOutlineIcon from "@material-ui/icons/AddCircleOutline";
    import { makeStyles } from "@material-ui/core/styles";
    import Modal from "@material-ui/core/Modal";
    import Button from "@material-ui/core/Button";
    
    import CSVUploader from "./CSVUploader.jsx";
    
    const useStyles = makeStyles((theme) => ({
      paper: {
        margin: "0 auto",
        top: "25vh",
        position: "relative",
        width: 400,
        backgroundColor: theme.palette.background.paper,
        border: "2px solid #000",
        boxShadow: theme.shadows[5],
        padding: theme.spacing(2, 4, 3)
      }
    }));
    
    const CustomToolbar = (props) => {
      const { setDataForTable } = props;
      const classes = useStyles();
      const [open, setOpen] = useState(false);
      const [CSVData, setCSVData] = useState([]);
    
      // When CSVData is updated, parse it and pass it up to the Table:
      useEffect(() => {
        const dataArr = Array.from(CSVData).map((data) => {
          // Make sure values are truth before returning:
          if (data.data.name && data.data.city) {
            return {
              name: data.data.name,
              company: data.data.company,
              city: data.data.city,
              state: data.data.state
            };
          }
        });
        setDataForTable(dataArr);
      }, [CSVData, setDataForTable]);
    
      // Open and close modal
      const handleOpen = () => {
        setOpen(true);
      };
    
      const handleClose = () => {
        setOpen(false);
      };
    
      /* Custom Button to open upload modal */
      return (
        <>
          <Tooltip title={"Add data from CSV"}>
            <IconButton>
              <AddCircleOutlineIcon onClick={handleOpen} />
            </IconButton>
          </Tooltip>
          <Modal
            open={open}
            onClose={handleClose}
            aria-labelledby="simple-modal-title"
            aria-describedby="simple-modal-description"
          >
            <div className={classes.paper}>
              <h2 id="simple-modal-title">Upload CSV Data</h2>
              <CSVUploader setCSVData={setCSVData} />
              <Button onClick={handleClose}>Close Modal</Button>
            </div>
          </Modal>
        </>
      );
    };
    
    export default CustomToolbar;
    

    Table.jsx

    And here, we pass the customToolbar component to the table options:

    import React, { useState } from "react";
    import MUIDataTable from "mui-datatables";
    import CustomToolbar from "./CustomToolbar.jsx";
    
    const columns = [
      {
        name: "name",
        label: "Name",
        options: {
          filter: true,
          sort: true
        }
      },
      {
        name: "company",
        label: "Company",
        options: {
          filter: true,
          sort: true
        }
      },
      {
        name: "city",
        label: "City",
        options: {
          filter: true,
          sort: true
        }
      },
      {
        name: "state",
        label: "State",
        options: {
          filter: true,
          sort: true
        }
      }
    ];
    
    const Table = () => {
      // Parse csv data from CustomToolbar:
      const [dataForTable, setDataForTable] = useState();
    
      // Custom Table options with custom toolbar:
      const options = {
        filterType: "checkbox",
        customToolbar: () => {
          return <CustomToolbar setDataForTable={setDataForTable} />;
        }
      };
    
      // Table
      return (
        <MUIDataTable
          title={"Employee List"}
          data={dataForTable}
          columns={columns}
          options={options}
        />
      );
    };
    
    export default Table;