Search code examples
reactjsfirebasegoogle-cloud-firestoremui-datatable

How to delete a row from a DataGrid that is connected to Firebase?


I have a DataGrid table with data that comes from Firebase and I wanted to know how can I delete and update the firebase information ?

I have this piece of code that deletes the row and it does works BUT because I haven't add anything to update the firebase it will not delete it permanently (which makes perfect sense):

Edit: Deleted unnecessary piece of code to just leave delete function this is just after a row has been check then it let's you delete that checked row (and it works) but I don't see space (it brings out compile errors) to add the firebase delete() function in that piece of code.

          <IconButton
            onClick={() => {
              const selectedIDs = new Set(selectionModel);
              setEstudiantes((r) => 
              r.filter((x) => 
              !selectedIDs.has(x.id)
              ));
            }}
          >
            <DeleteOutlinedIcon />
          </IconButton>

This is how I do the check of the rows (and it does work):

checkboxSelection
        //Store Data from the row in another variable
        onSelectionModelChange = {(id) => {
          setSelectionModel(id);
          const selectedIDs = new Set(id);
          const selectedRowData = estudiantes.filter((row) =>
            selectedIDs.has(row.id)
          );
          setEstudiantesData(selectedRowData)
        }
      }
        {...estudiantes}

However I do have the delete function that connects with my firebase and deletes documents that I did before migrating to MUI DataGrid but I do not know how to integrated it. This is how you delete something in firebase usually

db.collection("usuarios")
.doc(user.uid)
.collection("estudiantes")
.doc(document name variable)
.delete();

Thank you any tip/help is welcome.

*UPDATE this is how it looks

enter image description here

it does the delete as intended but it doesn't update the firebase and idk where to add the code that does that because w/e I try to add it it comes out as an error:

enter image description here

if I just refresh it comes back:

enter image description here

UPDATE Adding the code of the DataGrid:

return (
      <Container fixed>
      <Box mb={5} pt={2} sx={{textAlign:'center'}}>
      <Button
      startIcon = {<PersonAddIcon />} 
      variant = "contained" 
      color = "primary" 
      size = "medium" 
      onClick={crearEstudiante} >
      Crear Estudiantes
      </Button>
      <Box pl={25} pt={2} mb={2} sx={{height: '390px', width: "850px", textAlign:'center'}}>
      <DataGrid
        rows={estudiantes}
        columns={columns}
        pageSize={5}
        rowsPerPageOptions={[5]}

        components={{
          Toolbar: CustomToolbar,
        }}

        checkboxSelection
        //Store Data from the row in another variable
        onSelectionModelChange = {(id) => {
          setSelectionModel(id);
          const selectedIDs = new Set(id);
          const selectedRowData = estudiantes.filter((row) =>
            selectedIDs.has(row.id)
          );
          setEstudiantesData(selectedRowData)
        }
      }
        {...estudiantes}
        
      />
      </Box>
      <Button
      startIcon = {<ShoppingCartSharpIcon />} 
      variant = "contained" 
      color = "primary" 
      size = "medium" 
      onClick={realizarPedidos} >
      Crear pedido
      </Button>
      </Box></Container>
    )

Update Adding picture of the error I get when I try to add the logic to update the firebase, doesn't matter where I put it inside the delete logic it just gives me an error, I honestly do not know where to put it since I don't understand very well the selection of MUI on DataGrid

enter image description here

Update Adding my whole code:

import React, { useState, useEffect} from 'react'
import {db} from './firebase';
import { useHistory } from 'react-router-dom';
import "./ListadoEstudiantes.css"
import { DataGrid, 
  GridToolbarContainer, GridToolbarFilterButton, GridToolbarDensitySelector} from '@mui/x-data-grid';
import { Button, Container } from "@material-ui/core";
import { IconButton} from '@mui/material';
import PersonAddIcon from '@mui/icons-material/PersonAddSharp';
import ShoppingCartSharpIcon from '@mui/icons-material/ShoppingCartSharp';
import DeleteOutlinedIcon from '@mui/icons-material/DeleteOutlined';
import { Box } from '@mui/system';

function ListadoEstudiantes({user}) {

  const history = useHistory("");
  const crearEstudiante = () => {
    history.push("/Crear_Estudiante");
  };

 const [estudiantesData, setEstudiantesData] = useState([])

 const parseData = {
  pathname: '/Crear_Pedidos',
  data: estudiantesData
}

const realizarPedidos = () => {
  if(estudiantesData == 0)
  {
    window.alert("Seleccione al menos un estudiante")
  }
  else {
    history.push(parseData);
  }
};

 function CustomToolbar() {
  return (
    <GridToolbarContainer>
      <GridToolbarFilterButton />
      <GridToolbarDensitySelector />
    </GridToolbarContainer>
  );
}


const [estudiantes, setEstudiantes] = useState([]);
const [selectionModel, setSelectionModel] = useState([]);
  const columns = [
  { field: 'id', headerName: 'ID', width: 100 },

  {field: 'nombre', headerName: 'Nombre', width: 200},

  {field: 'colegio', headerName: 'Colegio', width: 250},

  {field: 'grado', headerName: 'Grado', width: 150},
    {
      field: "delete",
      width: 75,
      sortable: false,
      disableColumnMenu: true,
      renderHeader: () => {
        return (
          <IconButton
            onClick={() => {
              const selectedIDs = new Set(selectionModel);
              setEstudiantes((r) => 
              r.filter((x) => 
              !selectedIDs.has(x.id)
              ));
            }}
          >
            <DeleteOutlinedIcon />
          </IconButton>
        );
      }
    }
  ];

  const deleteProduct = (estudiante) => {
    if (window.confirm('Quiere borrar este estudiante ?')){
        db.collection("usuarios").doc(user.uid).collection("estudiantes").doc(estudiante).delete();
    }
}

useEffect(() => {
}, [estudiantesData])

 const estudiantesRef = db.collection("usuarios").doc(user.uid).collection("estudiantes")
 useEffect(() => {
  estudiantesRef.onSnapshot(snapshot => {
    const tempData = [];
    snapshot.forEach((doc) => {
      const data = doc.data();
      tempData.push(data);
    });
    setEstudiantes(tempData);
    
    console.log(estudiantes)
  })
 }, []);

 useEffect (() => {
  const estData = window.localStorage.getItem("estudiantes");
  setEstudiantes(JSON.parse(estData))
}, [])

 useEffect (() => {
   window.localStorage.setItem("estudiantes", JSON.stringify(estudiantes))
 })

    return (
      <Container fixed>
      <Box mb={5} pt={2} sx={{textAlign:'center'}}>
      <Button
      startIcon = {<PersonAddIcon />} 
      variant = "contained" 
      color = "primary" 
      size = "medium" 
      onClick={crearEstudiante} >
      Crear Estudiantes
      </Button>
      <Box pl={25} pt={2} mb={2} sx={{height: '390px', width: "850px", textAlign:'center'}}>
      <DataGrid
        rows={estudiantes}
        columns={columns}
        pageSize={5}
        rowsPerPageOptions={[5]}

        components={{
          Toolbar: CustomToolbar,
        }}

        checkboxSelection
        //Store Data from the row in another variable
        onSelectionModelChange = {(id) => {
          setSelectionModel(id);
          const selectedIDs = new Set(id);
          const selectedRowData = estudiantes.filter((row) =>
            selectedIDs.has(row.id)
          );
          setEstudiantesData(selectedRowData)
        }
      }
        {...estudiantes}
        
      />
      </Box>
      <Button
      startIcon = {<ShoppingCartSharpIcon />} 
      variant = "contained" 
      color = "primary" 
      size = "medium" 
      onClick={realizarPedidos} >
      Crear pedido
      </Button>
      </Box></Container>
    )
}

export default ListadoEstudiantes

Solution

  • So after you filter estudiantes, you're left with the items that the user does not want to delete. But before we do that, we're going to have to get the items that the user wants to delete so we can delete them from Firebase.

    You could replace the onClick function of the delete button with:

    onClick={() => {
    const selectedIDs = new Set(selectionModel);
    estudiantes.filter((x) =>
    selectedIDs.has(x.id)).map( x => {
    db.collection("usuarios").doc(user.uid).collection("estudiantes").doc(x.uid).delete()
    })
    )
    ////If NOT updating from db add this 
    setEstudiantes(estudiantes.filter((x) =>
    !selectedIDs.has(x.id)))
    }}
    

    Items that the user wants to delete are in selectedIDs so we need to use selectedIDs.has(x.id) instead of !selectedIDs.has(x.id). Now we're left with an array that includes only the items for deletion. We map this array to delete each one of these selected items. By using the map method.

    After this, you can filter estudiantes since now we don't need the items we just deleted from Firebase. (you can skip this one if you're updating from firebase as the new data won't include deleted items).

    Please let me know if this is what you were looking for.