I'm using DataGrid from MUI, it does have a checkbox function and I want to use it so that when I check it it adds the row data to a variable (the id, name, etc etc) so I can use it somewhere else with useLocation but it doesn't seem to be working ? I did a small test just to see if it was doing anything but it doesn't even show the console.log there's what I try:
.........
const [studentsID, setStudentsID] = useState([]);
function currentlySelected(estudiantes) {
setStudentsID(estudiantes)
console.log(studentsID)
}
...........
<DataGrid
rows={estudiantes}
columns={columns}
pageSize={5}
rowsPerPageOptions={[5]}
checkboxSelection
onSelectionChange={currentlySelected}
components={{
Toolbar: CustomToolbar,
}}
/>
All I want to do is to be able to send data to another page so I can work with the uid of the data and grab internal values such as (name, lastname) and that sort of thing let me know if you require anything else, any help/tips/documentation is welcome.
UPDATED This is my whole code in case you need it:
import React, { useState, useEffect, Fragment } from 'react'
import {db} from './firebase';
import { useHistory, useLocation } from 'react-router-dom';
import "./ListadoEstudiantes.css"
import * as locales from '#mui/material/locale';
import { DataGrid,
GridToolbarContainer,
GridToolbarColumnsButton,
GridToolbarFilterButton,
GridToolbarExport,
GridToolbarDensitySelector } from '#mui/x-data-grid';
import { Button, Container } from "#material-ui/core";
import PersonAddIcon from '#mui/icons-material/PersonAddSharp';
import { Box } from '#mui/system';
function ListadoEstudiantes({user}) {
const history = useHistory("");
const crearEstudiante = () => {
history.push("/Crear_Estudiante");
};
const [estudiantes, setEstudiantes] = useState([]);
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);
})
}, []);
function CustomToolbar() {
return (
<GridToolbarContainer>
<GridToolbarFilterButton />
<GridToolbarDensitySelector />
</GridToolbarContainer>
);
}
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}
]
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} sx={{height: '390px', width: "800px", textAlign:'center'}}>
<DataGrid
rows={estudiantes}
columns={columns}
pageSize={5}
rowsPerPageOptions={[5]}
components={{
Toolbar: CustomToolbar,
}}
checkboxSelection
onSelectionModelChange={(id) => {
const selectedIDs = new Set(id);
const selectedRowData = estudiantes.filter((row) =>
selectedIDs.has(row.id.toString())
);
console.log(selectedRowData, selectedIDs );
}}
{...estudiantes}
/>
</Box></Box></Container>
)
}
export default ListadoEstudiantes
UPDATE No longers grants me an error but it doesn't seem to be saving the data
Related
On initial page load the data (users) is successfully being captured in Redux DevTools however, the useSelector does not receive the state right away. Once I refresh the page, the data is successfully saved in the users variable. Because of this the entire page breaks since the table <DataGrid requires rows to contain data and at first users is undefined.
import React, { useEffect, useState } from "react";
import "./UserList.css";
import { DataGrid } from "#material-ui/data-grid";
import { useDispatch, useSelector } from "react-redux";
import { DeleteOutline } from "#material-ui/icons";
import { format } from "timeago.js";
import { Link } from "react-router-dom";
import { getUsers } from "../../redux/apiCalls";
import { deleteUser } from "../../redux/apiCalls";
const UserList = () => {
const dispatch = useDispatch();
useEffect(() => {
getUsers(dispatch);
}, [dispatch]);
const users = (useSelector((state) => state?.user?.users));
const handleDelete = (id) => {
deleteUser(id, dispatch);
window.location.reload();
};
const columns = [
{ field: "_id", headerName: "ID", width: 180 },
{
field: "user",
headerName: "User",
width: 200,
renderCell: (params) => {
return <div className="userListUser">{params.row.username}</div>;
},
},
{
field: "email",
headerName: "Email",
width: 200,
},
{
field: "isAdmin",
headerName: "isAdmin",
width: 150,
},
{
field: "createdAt",
headerName: "Account Created",
width: 180,
},
{
field: "action",
headerName: "Action",
width: 150,
renderCell: (params) => {
return (
<>
<Link to={"/user/" + params.row._id}>
<button className="userListEdit">Edit</button>
</Link>
<DeleteOutline
className="userListDelete"
onClick={() => handleDelete(params.row._id)}
/>
</>
);
},
},
];
console.log(users);
return (
<div className="userList">
<DataGrid
rows={users}
columns={columns}
getRowId={(row) => row._id}
pageSize={10}
rowsPerPageOptions={[10]}
checkboxSelection
disableSelectionOnClick
/>
</div>
);
};
export default UserList;
Try doing the following
return (
<div className="userList">
{users && (
<DataGrid
rows={users}
columns={columns}
getRowId={(row) => row._id}
pageSize={10}
rowsPerPageOptions={[10]}
checkboxSelection
disableSelectionOnClick
/>
)}
</div>
);
Following Material-UI docs I've implemented a search filter on Datagrid table, but encoutered a problem there.
Search filter functionality works fine, but while clearing input value, table data doesn't update.
I tried to update personData state if input value changes, but didn't help.
Here is the code and sandbox link
import ClearIcon from "#mui/icons-material/Clear";
import SearchIcon from "#mui/icons-material/Search";
import Box from "#mui/material/Box";
import IconButton from "#mui/material/IconButton";
import data from "./data.json";
import TextField from "#mui/material/TextField";
import { DataGrid } from "#mui/x-data-grid";
import React, { useState } from "react";
const columns = [
{ field: "name", headerName: "Name", flex: 1 },
{ field: "status", headerName: "Status", flex: 1 }
];
function escapeRegExp(value) {
return value.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
}
function QuickSearchToolbar(props) {
return (
<div>
<TextField
variant="standard"
value={props.value}
onChange={props.onChange}
placeholder="Search…"
InputProps={{
startAdornment: <SearchIcon fontSize="small" />,
endAdornment: (
<IconButton
title="Clear"
aria-label="Clear"
size="small"
style={{ visibility: props.value ? "visible" : "hidden" }}
onClick={props.clearSearch}
>
<ClearIcon fontSize="small" />
</IconButton>
)
}}
/>
</div>
);
}
const WindParkTable = () => {
const [searchText, setSearchText] = useState("");
const [personData, setPersonData] = useState(data || []);
const requestSearch = React.useCallback(
(searchValue) => {
setSearchText(searchValue);
const searchRegex = new RegExp(escapeRegExp(searchValue), "i");
const filteredRows = personData.filter((row) => {
return Object.keys(row).some((field) => {
return searchRegex.test(row[field].toString());
});
});
setPersonData(filteredRows);
},
[setPersonData, personData]
);
return (
<Box sx={{ height: 500, width: "100%", mt: "150px" }}>
{columns && (
<DataGrid
components={{ Toolbar: QuickSearchToolbar }}
rows={personData}
columns={columns}
componentsProps={{
toolbar: {
value: searchText,
onChange: (event) => requestSearch(event.target.value),
clearSearch: () => requestSearch("")
}
}}
/>
)}
</Box>
);
};
export default WindParkTable;
You are losing the original personData when you call to setPersonData(filteredRows). You have to filter in data instead of personData in your WindParkTable, something like this:
const filteredRows = data.filter((row) => {
return Object.keys(row).some((field) => {
return searchRegex.test(row[field].toString());
});
});
This is what I'm trying to achieve, the current issues are:
the background is currently affecting only the container, I want it to take the entire place
there has to be space in between the cards and padding inside the cards
import { useState, useEffect } from 'react';
import type { NextPage } from 'next';
import Container from '#mui/material/Container';
import Box from '#mui/material/Box';
import { DataGrid, GridColDef } from '#mui/x-data-grid';
import { Card, Paper } from '#mui/material';
import Skeleton from '#mui/material/Skeleton';
import { amber, orange } from '#mui/material/colors';
import FormOne from './../src/FormOne';
const columns: GridColDef[] = [
{ field: 'id', headerName: 'ID' },
{ field: 'title', headerName: 'Title', width: 300 },
{ field: 'body', headerName: 'Body', width: 600 },
];
const LoadingSkeleton = () => (
<Box
sx={{
height: 'max-content',
}}
>
{[...Array(10)].map((_) => (
<Skeleton variant="rectangular" sx={{ my: 4, mx: 1 }} />
))}
</Box>
);
const Home: NextPage = () => {
const [posts, setPosts] = useState([]);
const [loading, setLoading] = useState(true);
// fetch data from fake API
useEffect(() => {
setInterval(
() =>
fetch('https://jsonplaceholder.typicode.com/posts')
.then((response) => response.json())
.then((data) => {
setPosts(data);
setLoading(false);
}),
3000
);
}, []);
return (
<Container
maxWidth="lg"
sx={{
background: `linear-gradient(to right, ${amber[300]}, ${orange[500]})`,
}}
>
<Card>
<FormOne />
</Card>
<Card>
<Paper sx={{ height: '300px', width: '100%' }}>
<DataGrid
rows={posts}
columns={columns}
pageSize={10}
// autoHeight
rowsPerPageOptions={[10]}
disableSelectionOnClick
disableColumnMenu
disableColumnSelector
components={{
LoadingOverlay: LoadingSkeleton,
}}
loading={loading}
/>
</Paper>
</Card>
</Container>
);
};
export default Home;
First off, you will need to add remove margin and apply 100% of height to body and #root element. I have added this so style.css imported inside index.tsx
body {
margin: 0;
height: 100%;
}
#root {
height: 100%;
}
Next step would be to set maxWidth props to false, so it will be fulwidth.
I have added of course more stylings to your example to achieve the needed result(I hope i did it the way you imagined).
You can preview codesandbox here and edit the code here
p.s. I didnt have your FormOne component so I replaced it for now with simple input
I wanna know how to delete rows from the DataGrid from Material-UI by using the checkboxes in React. I haven't find any proper tutorial for doing this on DataGrid although I found one for MaterialTable but is not the same.
Any help is welcome.
UPDATE
My full code after adapt solution:
import React, { useState, useEffect, Fragment } from 'react'
import {db} from './firebase';
import { useHistory, useLocation } from 'react-router-dom';
import "./ListadoEstudiantes.css"
import * as locales from '#mui/material/locale';
import { DataGrid,
GridRowsProp, GridColDef,
GridToolbarContainer, GridToolbarColumnsButton, GridToolbarFilterButton, GridToolbarExport, 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 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(estudiantesData);
}
};
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 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);
})
}, []);
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} 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)
console.log(estudiantesData);
}
}
{...estudiantes}
/>
</Box></Box></Container>
)
}
export default ListadoEstudiantes
UPDATE
Everything works! thank you
You can keep track of the currently selected IDs via selectionModel/onSelectionModelChange props, and perform the necessary action when the user click the IconButton on the header. Because renderHeader callback doesn't provide the selection state, I have to make use of closure by putting the columns definition inside the function body so I can reference selectionModel in the callback:
const [rows, setRows] = React.useState(_rows);
const [selectionModel, setSelectionModel] = React.useState([]);
const columns: GridColDef[] = [
{ field: "col1", headerName: "Column 1", width: 150 },
{ field: "col2", headerName: "Column 2", width: 150 },
{
field: "delete",
width: 75,
sortable: false,
disableColumnMenu: true,
renderHeader: () => {
return (
<IconButton
onClick={() => {
const selectedIDs = new Set(selectionModel);
// you can call an API to delete the selected IDs
// and get the latest results after the deletion
// then call setRows() to update the data locally here
setRows((r) => r.filter((x) => !selectedIDs.has(x.id)));
}}
>
<DeleteIcon />
</IconButton>
);
}
}
];
return (
<div style={{ height: 400, width: "100%" }}>
<DataGrid
rows={rows}
columns={columns}
checkboxSelection
onSelectionModelChange={(ids) => {
setSelectionModel(ids);
}}
/>
</div>
);
I have used "react-useanimations" plugin, when i run my project showing me the following error.
Property 'animationKey' does not exist on type 'IntrinsicAttribute
common.js-> common functions are written here (simple js file)
myjob.tsx-> actual getTag function used on this page (typescript page)
// Common.js file
import React from "react";
import UseAnimations from "react-useanimations";
export function getTag(tag: any) {
if (tag === 'DL')
return (
<UseAnimations animationKey="github" size={56} style={{ padding: 100 }} />
);
}
// myjob.tsx
import React, { useState, useEffect } from "react";
import SVG from "react-inlinesvg";
import { Link } from "react-router-dom";
import { Alert, Nav, Tab } from "react-bootstrap";
import { toAbsoluteUrl } from "../../_metronic/_helpers";
import { utcToDate, getTag } from "../../utils/common";
import Icon from '#material-ui/core/Icon';
import { MDBDataTableV5 } from 'mdbreact';
import { Dropdown, Button } from "react-bootstrap";
import { DropdownCustomToggler } from "../../_metronic/_partials/dropdowns";
import Paper from '#material-ui/core/Paper';
import Draggable from 'react-draggable';
import { getUserJobList, deleteJobById } from "../../app/modules/Job/_redux/jobCrud";
import { shallowEqual, useSelector } from "react-redux";
export function MyJobs(props: any) {
const [open, setOpen] = React.useState(false);
const [openSnackbar, setOpenSnackbar] = React.useState(false);
const [deleteJobId, setDeleteJobId] = useState("");
const [key, setKey] = useState("Month");
const [msg, setMsg] = useState("")
const [type, setType] = useState<"success" | "primary" | "secondary" | "danger" | "warning" | "info" | "dark" | "light" | undefined>("success")
const [jpbList, setJpbList] = useState([])
const [displayBy, setDisplayBy] = useState(false)
const [folders, setFolders] = useState()
const user = useSelector((state: any) => state.auth.user, shallowEqual);
const [datatable, setDatatable] = useState({
columns: [
{
label: '#',
field: 'icon',
width: 150,
attributes: {
'aria-controls': 'DataTable',
'aria-label': 'Name',
},
},
{
label: 'Job Name',
field: 'name',
width: 150,
attributes: {
'aria-controls': 'DataTable',
'aria-label': 'Name',
},
},
{
label: 'Proccesed Date',
field: 'createdDttm',
width: 270,
},
{
label: 'Status',
field: 'status',
width: 270,
},
{
label: 'Action',
field: 'action',
width: 270,
},
],
rows: [{}],
});
useEffect(() => {
if (!jpbList.length) {
getList();
}
}, []);
const getList = async () => {
getUserJobList(user.id)
.then((res: any) => {
if (res.status == 200 && res.data) {
let rows: any = [];
res.data.map((row: any) => {
rows.push(
{
icon:<img src={row.thumbnail} style={{ maxWidth: '50px', maxHeight: '50px' }} />,
name: row.name,
createdDttm: utcToDate(row.createdDttm),
status: getTag(row.status),
action: <div style={{ width: '120px' }}>
{/* begin::Toolbar */}
<div className="d-flex justify-content-end">
{
row.status == "CO" ?
<Link to={`myjobs/markerpage/${row.id}`} className="btn btn-icon btn-sm mx-3">
<span className="svg-icon svg-icon-md svg-icon-primary">
<Icon className='fa fa-play' color="action" />
</span>
</Link> : ""
}
< Dropdown className="dropdown dropdown-inline" alignRight>
<Dropdown.Toggle
id="dropdown-toggle-top-user-profile"
as={DropdownCustomToggler}
>
<i className="ki ki-bold-more-hor"></i>
</Dropdown.Toggle>
<Dropdown.Menu className="dropdown-menu dropdown-menu-sm dropdown-menu-right">
</Dropdown.Menu>
</Dropdown>
</div>
{/* end::Toolbar */}</div >,
}
)
});
let dt: any = [];
dt.columns = datatable.columns;
dt.rows = rows;
setDatatable(dt);
setJpbList(res.data);
} else {
setMsg("Something went wrong please try again later.")
setType("danger")
}
})
.catch((e: any) => {
setMsg("Something went wrong please try again later.")
setType("danger")
});
}
return (
<>
<MDBDataTableV5 hover entriesOptions={[10, 20, 50]} entries={10} pagesAmount={4} data={datatable} searchTop searchBottom={false} />
</>);
}
First import icon which you want.
import UseAnimations from "react-useanimations";
import activity from 'react-useanimations/lib/activity'
In view or in render use like this
<UseAnimations animation={activity} autoplay={true} loop={true} size={20} style={{ paddingLeft: 10 }} />