I would like to enable Delete/Update of column with buttons I defined in 'customBodyRender'
mui-datatables support customized components inside table cells, I like that. I have made it to put some buttons in one column of the table, so user can interact with each row's data.
For each row, I have some columns with data, and one columns with 'delete' and 'update' button, I need to enable the buttons to work.
For example, one row of table look like this:
Alex | 30 |
I cannot delete rows from customized component with 'customBodyRender'
| Tech | Version |
|--------------|---------|
| Material-UI | latest |
| MUI-datatables | latest |
| React | latest |
| browser | chrome |
| etc | |
@gregnb
Finally I figure out a way to change the Table's data with buttons in 'customBodyRender'.
My original question is essentially asking: let's say we have a parent component
Because the relation of
axios.get(URL)
.then(function (response) {
let data = response.data;
if(data){
current.props.fetchData(data); // Action to fetch data and save it to redux store
}
})
.catch(function (error) {
console.log(error);
});
}`
Then I will load the data from Redux store.
function mapStateToProps(state) {
return {
data: state.data
}
}
Then feed it to MUI datatable:
<MUIDataTable
title={"List"}
data={this.props.data}
columns={columns}
options={options}
/>
Then in my child component
Let's look at one example of deleting the current row. I created an Action method called deleteData(id, list), it will remove the row of data with specified ID, then return the rest array list to Redux store.
I have a button:
<Button onClick={this.handleDelete} color="primary" autoFocus>
Delete
</Button>
It will call a handleDelete method, in the method first we call a backend API to remove data, if success, then we will call the Action method 'deleteData to remove the same data from Redux store:
` handleDelete = () => {
var current = this;
var id = this.props.value;
var {deleteData, data_list} = this.props;
// deleteData is a Action Function, data_list is the Redux store data, both of them all passed to
var delete_url = ${DeleteURL}/${id};
axios.delete(delete_url)
.then(function(res) {
deleteData(id, data_list); // update Redux store
})
.catch(function (error) {
console.log(error);
});
}`
Because our parent component is connect with Redux store, when we update the table data in our child component, the change of state update the parent component. And you see the row is deleted in the front end web page. Bingo!
Hey @zhouyuhang ! This is exactly the problem I'm facing with my current MUI-datatable build. I'm trying to add an edit and delete button as well utilizing the custom body render, I'm very close to getting right, but can't seem to refactor properly using I'm utilizing react and redux for state management. Really, I'm struggling with making button links to edit forms for each row, which would require maintaining the id for each row.
Would you be willing to assist or share your code? Thanks!
Same here... I can't achieve to make a delete request to my API when pressing the default Delete Icon (which triggers the onRowsDelete built in method. I don't know how to pass that row's ID to the function.(currently I have data from my db displayed con the table, so I need to pass to the onRowsDelete the id from my db). Do you know how to handle this? Thanks in advance
@nultron Were you able to figure this out? I was able to figure out a working solution and could help you if need be. There were some interesting configurations that I had to do, but for the most part the package wasn't as opinionated as I initially thought. Let me know!
yekijnuy Can you help me with the configuration you did?
@marianalucut7 Sure - first what are you trying to render? Send me some details and I'll be more than happy to help if you are still stuck
If you are trying to find the row id , everything you need is located in the tableMeta.
Try this inside your customBodyRender function
const rowId = tableMeta.rowData
console.log(rowId)
I had mine working the other day to render a edit icon but now for some reason it is not working.
Please let me know if you see a problem with this code.
`const columns = [
{
name: "ID",
options: {
display: false,
}
},
"Client Name",
"Date",
"Type",
"Memo",
"Status",
"Reatainer Rec",
{
name: "Edit",
options: {
display: true,
onCellClick: (rowIndex) => {this.handleEdit(rowIndex)},
customBodyRender: (value, tableMeta, updateValue) => {
const rowId = tableMeta.rowData
console.log(rowId)
// tableMeta contains all the info that is needed
return (
<Icon name="edit" size="large" color="green" onClick={ e => this.handleEdit(rowId, e)}>
</Icon>
);
},
}
}
];
`
How can we update the changed data to the database without using redux in the custom body render?
Hello,
I added my action buttons using customBodyRender:
{
name: "Action",
options: {
filter: true,
sort: false,
empty: true,
customBodyRender: () => {
return (
<ActionButtons
onView={this.onView}
onEdit={this.onEdit}
onDelete={this.onDelete}
/>
);
}
}
},
And in table options, I use onRowClick to get the data (included an object of the component
const options = {
filter: true,
download: false,
selectableRows: false,
filterType: "dropdown",
responsive: "scroll",
rowsPerPage: 10,
customToolbar: () => (
<CustomToolbar
handleFormOpen={this.handleFormOpen}
/>
),
onRowClick: (event, rowData) => {
this.handleClickedActionButton(event, rowData);
},
};
As I have 3 buttons in one cell (view, edit and delete) for each row, I need to know which button was clicked in order to perform an action to the data (call a function).
I tried using event.currentTarget to get the id of the button clicked, use that id in a switch statement in order to identify which one was and base on that call the correct function.
Something like this:
onRowClick: (event, rowData) => {
this.handleClickedActionButton(event, rowData);
},
};
//
handleClickedActionButton = (event, rowData ) => {
const buttonID = event.currentTarget.dataset.id;
switch (buttonID) {
case "btnView":
console.log("View");
break;
case "btnEdit":
console.log("Edit");
break;
case "btnDelete":
console.log("Delete");
break;
default: console.log("No action button clicked.");
}
};
But I just get an error saying "Type error: event.currentTarget is undefined".
How can I implement this idea in a better way? T.T
Hi, i read all comments and i had similar issue in my project i solve it using React hooks, sharing state and actions using a local context, here my example, i hope helping any;
context.js
import React from "react";
const TableContext = React.createContext({
actions: {},
stateTable: {},
filterOptions: {}
});
export function useTableContext() {
return React.useContext(TableContext);
}
export default TableContext;
index.js
import TableContext from './context';
function EnrolledContainer() {
const classes = useStyles();
const { actions, stateTable, filterOptions, handleClose, handleAddButton } = useEnrolledTable();
const { title, isLoading, open, tableData } = stateTable;
return (<TableContext.Provider value={{ actions, stateTable, filterOptions }}>
<Grid container spacing={8} className={classes.container}>
<Grid item xs={12} sm={12}>
<MUIDataTable
title={
<React.Fragment>
<span>
<span style={{ fontSize: "1.5em", fontWeight: 'bolder', textAlign: 'center' }} >{title}</span>
</span>
<span>
{!!isLoading && <CircularProgress size={24} thickness={6} style={{ marginLeft: 15, position: 'relative', top: 4, textAlign: 'center' }} />}
</span>
</React.Fragment>
}
data={tableData}
columns={getColumns(stateTable, actions, filterOptions)}
options={getOptions(stateTable, actions)}
/>
....
customBodyRender 馃憤
import { useTableContext } from '../context';
const ToggleButton = React.memo(props => {
const value = props[0]
const tableMeta = props[1]
const updateValue = props[2]
const { actions } = useTableContext();
const { modificatePeople, getRowData, openAlertDialog, closeAlertDialog, updateRow, enqueueSnackbar, closeSnackbar } = actions
const people = getRowData(tableMeta.rowIndex);
return <FormControlLabel
control={<Switch color="primary" checked={people && people.status} value={people && people.status ? "Activo" : "Inactivo"}
onChange={event => {
const value = event.target.checked;
people && openAlertDialog({
title: 'Cambiar estado ',
message: "Est谩 seguro(a) de " + ((status) ? "bloquear" : "activar") + " a " + people.fname
})
.then((accept) => {
if (accept) {
closeAlertDialog();
people.status = value;
updateRow(tableMeta.rowIndex, people)
people && modificatePeople({
id: people.id,
params: {
status: Number(value)
}
})
}
})
}}
/>}
/>
})
export default (...args) => {
return <ToggleButton {...args} />
}
Hi, I'm new to React and MUI-datatables. I have been creating a datatable where I am implementing CRUD. Everything else works perfectly apart from Update. I can only update the first row even when I click on the edit icon on other rows. Whenever I click on each edit icon in every row. A modal form pops up where I am supposed to update the details of a particular item (in this case, company). I am also using redux.
* Edit Clolumn*
{
name: "Edit",
options: {
filter: false,
sort: false,
empty: true,
customBodyRender: (value, tableMeta, updateValue) => {
const rowId = tableMeta.rowData[0]
return (
<div>
<EditIcon onClick={this.toggle} />
<Modal isOpen={this.state.modal} toggle={this.toggle}>
<ModalHeader toggle={this.toggle}>Update Company</ModalHeader>
<ModalBody>
<Form onSubmit={this.handleSubmit.bind(this, rowId)}>
<FormGroup>
<Label for='name'>Name</Label>
<Input
type='text'
name='name'
id='item'
placeholder='update name'
onChange={this.handleChange}
/>
<Label for='email'>Email</Label>
<Input
type='email'
name='email'
id='email'
placeholder='update email'
onChange={this.handleChange}
/>
<Label for='phone'>Phone</Label>
<Input
type='text'
name='phone'
id='phone'
placeholder='update phone'
onChange={this.handleChange}
/>
<Label for='website'>Website</Label>
<Input
type='url'
name='website'
id='website'
placeholder='update website'
onChange={this.handleChange}
/>
<Label for='address'>Address</Label>
<Input
type='text'
name='address'
id='address'
placeholder='update address'
onChange={this.handleChange}
/>
<Button color='dark' style={{ marginTop: '2rem' }} block>
Update Company
</Button>
</FormGroup>
</Form>
</ModalBody>
</Modal>
</div>
);
}
}
},
handleSubmit
handleSubmit = id => {
const company = {
name: this.state.name,
email: this.state.email,
phone: this.state.phone,
website: this.state.website,
address: this.state.address
};
// update company via updateCompany action
this.props.updateCompany(company, id);
//Close modal
this.toggle();
};
What could I be doing wrong. Or is there a better way to do this?
Hi, I'm new to React and MUI-datatables. I have been creating a datatable where I am implementing CRUD. Everything else works perfectly apart from Update. I can only update the first row even when I click on the edit icon on other rows. Whenever I click on each edit icon in every row. A modal form pops up where I am supposed to update the details of a particular item (in this case, company). I am also using redux.
* Edit Clolumn*
{ name: "Edit", options: { filter: false, sort: false, empty: true, customBodyRender: (value, tableMeta, updateValue) => { const rowId = tableMeta.rowData[0] return ( <div> <EditIcon onClick={this.toggle} /> <Modal isOpen={this.state.modal} toggle={this.toggle}> <ModalHeader toggle={this.toggle}>Update Company</ModalHeader> <ModalBody> <Form onSubmit={this.handleSubmit.bind(this, rowId)}> <FormGroup> <Label for='name'>Name</Label> <Input type='text' name='name' id='item' placeholder='update name' onChange={this.handleChange} /> <Label for='email'>Email</Label> <Input type='email' name='email' id='email' placeholder='update email' onChange={this.handleChange} /> <Label for='phone'>Phone</Label> <Input type='text' name='phone' id='phone' placeholder='update phone' onChange={this.handleChange} /> <Label for='website'>Website</Label> <Input type='url' name='website' id='website' placeholder='update website' onChange={this.handleChange} /> <Label for='address'>Address</Label> <Input type='text' name='address' id='address' placeholder='update address' onChange={this.handleChange} /> <Button color='dark' style={{ marginTop: '2rem' }} block> Update Company </Button> </FormGroup> </Form> </ModalBody> </Modal> </div> ); } } },handleSubmit
handleSubmit = id => { const company = { name: this.state.name, email: this.state.email, phone: this.state.phone, website: this.state.website, address: this.state.address }; // update company via updateCompany action this.props.updateCompany(company, id); //Close modal this.toggle(); };What could I be doing wrong. Or is there a better way to do this?
You would need to make your id column in the table to have display:'excluded'
is very easy, check this.... it's ok for me:
Add the event onRowsDelete on the options section:
const options = {
onRowsDelete: (rowData, rowState) => {
handleDeleteCat(rowData, rowState);
},
filter: false,
selectableRows: true,
filterType: 'dropdown',
responsive: 'stacked',
rowsPerPage: 10,
}
Create a function for getting the event, and get the row data index. Finally, get from the object list the index position and get the id. With it you can delete the row in your database:
const handleDeleteCat = (rowIndex, dataIndex) => {
const rowToDelete = rowIndex.data[0].dataIndex;
var idCatToDelete = props.state.productCategories.categoryList.categoriesList[rowToDelete][0];
};