Is there a way to show the action buttons(edit, delete etc.) only when hovering over a specific row?
I do not believe there is a way to do this.
@dmfarcas
I take that back - I was able to figure this out.. The only downside is it is a little hacky since you have to force a state change in order to re-render the edited row, otherwise the edited data does not show up...
import React, { useState } from "react";
import { render } from "react-dom";
import MaterialTable, { MTableBodyRow, MTableEditRow } from "material-table";
import tableIcons from "./TableIcons.js";
import { Edit } from "@material-ui/icons";
const rando = max => Math.floor(Math.random() * max);
const words = ["Paper", "Rock", "Scissors"];
const rawData = [];
for (let i = 0; i < 100; i++)
rawData.push({ id: rando(300), name: words[i % words.length] });
const columns = [
{ title: "Id", field: "id" },
{ title: "Name", field: "name" }
];
const App = () => {
const [data, setData] = useState(rawData);
const [hoveringOver, setHoveringOver] = useState('');
// This is the only downside.. very hacky
const [, setForceUpdate] = useState(0);
const forceUpdate = () => setForceUpdate(old => old + 1);
const handleRowHover = (event, propsData) => setHoveringOver(propsData.data.tableData.id);
const handleRowHoverLeave = (event, propsData) => setHoveringOver('');
const handleEditClick = (event, rowData) => {
rowData.tableData.editing = 'update';
forceUpdate();
}
return (
<MaterialTable
data={data}
columns={columns}
localization={{
header: { actions: <td style={{ width: '26px' }}></td> }
}}
actions={[
(rowData) => {
return hoveringOver !== "" && rowData.tableData.id === hoveringOver
? { icon: Edit, hidden: false, onClick: handleEditClick }
: { icon: Edit, hidden: true, onClick: ()=>{} }
},
]}
components={{
Row: props => {
return (
<MTableBodyRow
{...props}
onMouseEnter={e => handleRowHover(e, props)}
onMouseLeave={e => handleRowHoverLeave(e, props)}
/>
)
},
EditRow: props => {
return (
<MTableEditRow
{...props}
onEditingCanceled={(mode, rowData) => {
rowData.tableData.editing = undefined;
forceUpdate();
}}
onEditingApproved={(mode, newData, oldData) => {
const dataCopy = [...data];
dataCopy[oldData.tableData.id] = newData;
setData(dataCopy);
}}
/>
);
}
}}
icons={tableIcons}
/>
);
};
render(<App />, document.querySelector("#root"));
@oze4 How can we delete when hover on row, with confirmation text.
@keshavashiya you would follow a similar pattern to 'edit'.
// Demo code
import React, { useState } from "react";
import { render } from "react-dom";
import MaterialTable, { MTableBodyRow, MTableEditRow } from "material-table";
import { Delete as DeleteIcon } from '@material-ui/icons';
import tableIcons from "./TableIcons.js";
const originalData = ["Rock", "Paper", "Scissors"].map(word => ({
id: Math.floor(Math.random() * 300),
name: word
}));
const columns = [
{ title: "Id", field: "id" },
{ title: "Name", field: "name" }
];
function App() {
const [data, setData] = useState(originalData);
const [hoveringOver, setHoveringOver] = useState('');
// This is the only downside.. very hacky
const [, setForceUpdate] = useState(0);
const forceUpdate = () => setForceUpdate(old => old + 1);
const handleRowHover = (event, propsData) => setHoveringOver(propsData.data.tableData.id);
const handleRowHoverLeave = (event, propsData) => setHoveringOver('');
const handleEditClick = (event, rowData) => {
rowData.tableData.editing = 'delete';
forceUpdate();
}
return (
<MaterialTable
data={data}
icons={tableIcons}
columns={columns}
actions={[
rowData => {
return hoveringOver !== "" && rowData.tableData.id === hoveringOver
? { icon: DeleteIcon, hidden: false, onClick: handleEditClick }
: { hidden: true };
}
]}
components={{
Row: props => {
return (
<MTableBodyRow
{...props}
onMouseEnter={e => handleRowHover(e, props)}
onMouseLeave={e => handleRowHoverLeave(e, props)}
/>
);
},
EditRow: props => {
return (
<MTableEditRow
{...props}
onEditingApproved={(mode, newData, oldData) => {
if (oldData.tableData.editing === 'delete') {
const dataCopy = [...data];
dataCopy.splice(oldData.tableData.id, 1);
setData(dataCopy);
}
}}
/>
);
}
}}
/>
);
}
render(<App />, document.querySelector("#root"));
@oze4 I tried similar method but I'm not able to display confirmation delete text It directly delete row.
@keshavashiya did you check out my demo? It prompts for confirmation, etc.. is that what you're looking for?
@oze4 Thanks I want this type of solution.
@dmfarcas
I take that back - I was able to figure this out.. The only downside is it is a little hacky since you have to force a state change in order to re-render the edited row, otherwise the edited data does not show up...
import React, { useState } from "react"; import { render } from "react-dom"; import MaterialTable, { MTableBodyRow, MTableEditRow } from "material-table"; import tableIcons from "./TableIcons.js"; import { Edit } from "@material-ui/icons"; const rando = max => Math.floor(Math.random() * max); const words = ["Paper", "Rock", "Scissors"]; const rawData = []; for (let i = 0; i < 100; i++) rawData.push({ id: rando(300), name: words[i % words.length] }); const columns = [ { title: "Id", field: "id" }, { title: "Name", field: "name" } ]; const App = () => { const [data, setData] = useState(rawData); const [hoveringOver, setHoveringOver] = useState(''); // This is the only downside.. very hacky const [, setForceUpdate] = useState(0); const forceUpdate = () => setForceUpdate(old => old + 1); const handleRowHover = (event, propsData) => setHoveringOver(propsData.data.tableData.id); const handleRowHoverLeave = (event, propsData) => setHoveringOver(''); const handleEditClick = (event, rowData) => { rowData.tableData.editing = 'update'; forceUpdate(); } return ( <MaterialTable data={data} columns={columns} localization={{ header: { actions: <td style={{ width: '26px' }}></td> } }} actions={[ (rowData) => { return hoveringOver !== "" && rowData.tableData.id === hoveringOver ? { icon: Edit, hidden: false, onClick: handleEditClick } : { icon: Edit, hidden: true, onClick: ()=>{} } }, ]} components={{ Row: props => { return ( <MTableBodyRow {...props} onMouseEnter={e => handleRowHover(e, props)} onMouseLeave={e => handleRowHoverLeave(e, props)} /> ) }, EditRow: props => { return ( <MTableEditRow {...props} onEditingCanceled={(mode, rowData) => { rowData.tableData.editing = undefined; forceUpdate(); }} onEditingApproved={(mode, newData, oldData) => { const dataCopy = [...data]; dataCopy[oldData.tableData.id] = newData; setData(dataCopy); }} /> ); } }} icons={tableIcons} /> ); }; render(<App />, document.querySelector("#root"));
A great solution for on hover row actions, thanks.
I found this solution using CSS, since above solution is correct but every time it's updating state and then whole component is rendering.
@dmfarcas , there is more easy way (imho) to do this. Just need to add class for the row.
Here is a demo - https://react-nhwuqk.stackblitz.io
I made the same on my project, but need also to show different icons based on what is it - draft || sent || scheduled
Most helpful comment
@dmfarcas
I take that back - I was able to figure this out.. The only downside is it is a little hacky since you have to force a state change in order to re-render the edited row, otherwise the edited data does not show up...
Check out a live demo here