I have a Material-UI DataGrid ponent 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 ponent 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;
I have a Material-UI DataGrid ponent 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 ponent 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;
Share
Improve this question
edited May 1, 2021 at 7:39
fuat
asked Apr 26, 2021 at 20:25
fuatfuat
1,8722 gold badges21 silver badges28 bronze badges
4
- I wonder where is Dialog ponent. – Marios Nikolaou Commented Apr 26, 2021 at 20:48
-
You arent placing any dialog ponent in the
renderCell
. – Medi Commented Apr 26, 2021 at 20:48 - @Medi it's impossible to open a dialog without having the implementation and display/hide on demand. – Marios Nikolaou Commented Apr 26, 2021 at 20:53
- Sorry I will add later the dialog ponent. But now I just want to set the state then I can pass it any ponent that desired. – fuat Commented Apr 26, 2021 at 20:57
2 Answers
Reset to default 2DataGrid
ponent 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;
Update - 2021
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>
</>
);
},
},