Reputation: 1842
I have a Material-UI DataGrid component that has edit and delete buttons in a row, but I can only do alert or console log,
Why there are buttons in a row because need dialogs when clicking the button, for example when the user clicks the delete button there will be a confirm dialog for delete action, or when click an edit button there will be a form dialog that updates the row,
Need to push the user to edit or delete only one item at the same time. So multiple selection is not allowed.
My question is how to get the row data in the component when clicking the button inside the column definition, in that case, click the Edit
or Delete
button.
Using "@material-ui/data-grid": "^4.0.0-alpha.26"
import Container from "@material-ui/core/Container";
import Grid from "@material-ui/core/Grid";
import Paper from "@material-ui/core/Paper";
import DeleteIcon from "@material-ui/icons/Delete";
import EditIcon from "@material-ui/icons/Edit";
import Button from "@material-ui/core/Button";
import AddIcon from "@material-ui/icons/Add";
import { makeStyles } from "@material-ui/core/styles";
import {
DataGrid,
GridColDef,
GridApi,
GridCellValue
} from "@material-ui/data-grid";
const columns: GridColDef[] = [
{ field: "id", headerName: "ID", width: 70 },
{ field: "name", headerName: "First name", width: 130 },
{ field: "surname", headerName: "Last name", width: 130 },
{
field: "edit",
headerName: "Edit",
sortable: false,
width: 130,
disableClickEventBubbling: true,
renderCell: (params) => {
const onClick = () => {
const api: GridApi = params.api;
const fields = api
.getAllColumns()
.map((c) => c.field)
.filter((c) => c !== "__check__" && !!c);
const thisRow: Record<string, GridCellValue> = {};
fields.forEach((f) => {
thisRow[f] = params.getValue(f);
});
// set to state rather then alert
return alert(JSON.stringify(thisRow, null, 4));
};
return (
<Button
variant="contained"
color="primary"
startIcon={<EditIcon />}
onClick={onClick}
>
Edit
</Button>
);
}
},
{
field: "delete",
headerName: "Delete",
sortable: false,
width: 130,
disableClickEventBubbling: true,
renderCell: (params) => {
const onClick = () => {
const api: GridApi = params.api;
const fields = api
.getAllColumns()
.map((c) => c.field)
.filter((c) => c !== "__check__" && !!c);
const thisRow: Record<string, GridCellValue> = {};
fields.forEach((f) => {
thisRow[f] = params.getValue(f);
});
// set to state rather then alert
return alert(JSON.stringify(thisRow, null, 4));
};
return (
<Button
variant="contained"
color="secondary"
startIcon={<DeleteIcon />}
onClick={onClick}
>
Delete
</Button>
);
}
}
];
const rows = [
{ id: 1, name: "Example 1", surname: "example" },
{ id: 2, name: "Example 2", surname: "example" }
];
export type User = {
id: number;
name: string;
surname: string;
};
const useStyles = makeStyles((theme) => ({
content: {
flexGrow: 1,
height: "100vh",
overflow: "auto"
},
appBarSpacer: theme.mixins.toolbar,
container: {
paddingTop: theme.spacing(4),
paddingBottom: theme.spacing(4)
},
paper: {
padding: theme.spacing(2),
display: "flex",
overflow: "auto",
flexDirection: "column",
elevation: 3
}
}));
const App = () => {
const classes = useStyles();
return (
<main className={classes.content}>
<div className={classes.appBarSpacer} />
<Container maxWidth="lg" className={classes.container}>
<Grid item xs={12}>
<Paper className={classes.paper}>
<DataGrid
rows={rows}
columns={columns}
pageSize={10}
columnBuffer={8}
autoHeight
/>
</Paper>
</Grid>
<Grid item xs={3} style={{ padding: 20 }}>
<Button
variant="contained"
color="primary"
startIcon={<AddIcon />}
onClick={() => {
console.log("new");
}}
>
New
</Button>
</Grid>
</Container>
</main>
);
};
export default App;
Upvotes: 0
Views: 14254
Reputation: 1842
DataGrid
component has a prop onCellClick
to handle event when user clicks any cell in the data grid. This prop use GridCellParams
type, just need to filter columns base on GridCellParams.colDef.field
attribute.
Code changed as below;
EDIT: According to the Material-UI documentation, GridCellParams property getValue
just changed. Now it takes two-parameter; getValue(id: GridRowId, field: string)
import Container from "@material-ui/core/Container";
import Grid from "@material-ui/core/Grid";
import Paper from "@material-ui/core/Paper";
import DeleteIcon from "@material-ui/icons/Delete";
import EditIcon from "@material-ui/icons/Edit";
import Button from "@material-ui/core/Button";
import { makeStyles } from "@material-ui/core/styles";
import {
DataGrid,
GridColDef,
GridApi,
GridCellValue,
GridCellParams
} from "@material-ui/data-grid";
import React, { useState } from "react";
import {
Dialog,
DialogTitle,
DialogContent,
DialogContentText,
DialogActions
} from "@material-ui/core";
const columns: GridColDef[] = [
{ field: "id", headerName: "ID", width: 70 },
{ field: "name", headerName: "First name", width: 130 },
{ field: "surname", headerName: "Last name", width: 130 },
{
field: "edit",
headerName: "Edit",
sortable: false,
width: 130,
disableClickEventBubbling: true,
renderCell: () => {
return (
<Button variant="contained" color="primary" startIcon={<EditIcon />}>
Edit
</Button>
);
}
},
{
field: "delete",
headerName: "Delete",
sortable: false,
width: 130,
disableClickEventBubbling: true,
renderCell: () => {
return (
<Button
variant="contained"
color="secondary"
startIcon={<DeleteIcon />}
>
Delete
</Button>
);
}
}
];
const rows = [
{ id: 1, name: "Example 1", surname: "example" },
{ id: 2, name: "Example 2", surname: "example" }
];
export type User = {
id: number;
name: string;
surname: string;
};
const useStyles = makeStyles((theme) => ({
content: {
flexGrow: 1,
height: "100vh",
overflow: "auto"
},
appBarSpacer: theme.mixins.toolbar,
container: {
paddingTop: theme.spacing(4),
paddingBottom: theme.spacing(4)
},
paper: {
padding: theme.spacing(2),
display: "flex",
overflow: "auto",
flexDirection: "column",
elevation: 3
}
}));
const App = () => {
const classes = useStyles();
const [selectedUser, setSelectedUser] = useState({} as User);
const [openDialog, setOpenDialog] = useState(false);
function currentlySelected(params: GridCellParams) {
const api: GridApi = params.api;
const value = params.colDef.field;
if (!(value === "edit" || value === "delete")) {
return;
}
const fields = api
.getAllColumns()
.map((c) => c.field)
.filter((c) => c !== "__check__" && !!c);
const thisRow: Record<string, GridCellValue> = {};
fields.forEach((f) => {
thisRow[f] = params.getValue(params.id, f);
});
const user = {} as User;
user["id"] = Number(thisRow["id"]);
user["name"] = thisRow["name"]!.toString();
user["surname"] = thisRow["surname"]!.toString();
setSelectedUser(user);
setOpenDialog(true);
}
const handleClose = () => {
setOpenDialog(false);
};
return (
<main className={classes.content}>
<div className={classes.appBarSpacer} />
<Container maxWidth="lg" className={classes.container}>
<Grid item xs={12}>
<Paper className={classes.paper}>
<DataGrid
rows={rows}
columns={columns}
pageSize={10}
columnBuffer={8}
autoHeight
onCellClick={currentlySelected}
/>
</Paper>
</Grid>
</Container>
<Dialog
open={openDialog}
onClose={handleClose}
aria-labelledby="form-dialog-title"
>
<DialogTitle id="form-dialog-title"> User </DialogTitle>
<DialogContent>
<DialogContentText id="alert-dialog-description">
{JSON.stringify(selectedUser)}
</DialogContentText>
</DialogContent>
<DialogActions>
<Button onClick={handleClose} color="primary">
Cancel
</Button>
<Button onClick={handleClose} color="primary">
Confirm
</Button>
</DialogActions>
</Dialog>
</main>
);
};
export default App;
Upvotes: 2
Reputation: 1627
06/08/2021 - Latest answer
The following ones work for me as expected.
const columns: GridColDef[] = [
{ field: 'id', headerName: 'ID', width: 100, hide: true },
{
field: 'action',
width: 130,
sortable: false,
renderCell: (params) => {
const onClickDelete = async () => {
return alert(JSON.stringify(params.row, null, 4));
};
const onClickEdit = async () => {};
return (
<>
<IconButton color="secondary" onClick={onClickDelete}>
<DeleteIcon />
</IconButton>
<IconButton color="secondary" onClick={onClickEdit}>
<EditIcon />
</IconButton>
</>
);
},
},
Upvotes: 0