Distinguish row clicks in Antd (ant design) table React component - reactjs

I'm using Ant Design table component: https://ant.design/components/table/#Table
In each row, I'm rendering a title and some link. For example:
Product 1
https://example.com/link/product/1
I'm using the onRow API to open a modal to edit the info for the row, which is working fine. However, the onRow event is also trigged if I click on the link. Is there a way to not trigger the onRow event if I just click on the link in the row, and still keep everything as normal if I click on anywhere on the row cell?
Note: my current work around is using an isEditing state flag, but it's not a good experience since I have to get into "edit mode" and set isEditing to true.

You'd better show your code usage of onRow and columns, If you use onRow.onClick like below:
<Table
onRow={(record, rowIndex) => {
return {
onClick: event => {}, // click row
};
}}
/>
You can custom render of link with Event.stopPropagation() like this:
const columns = [
{
dataIndex: "link",
title: "Link",
render: (value) => {
return (
<a
onClick={(event) => event.stopPropagation()}
href={value}
target="_blank"
>
Link
</a>
);
}
}
]

Related

How to know on which column the click event has happened in Antd Table?

I have an antd table in which I need to do some operations only when the click event happens on a specific column.
Currently, I am using the onRow prop in the table component as below
onRow={(record, rowIndex) => {
return {
onClick: (event) => {
// some operations
},
};
}}
With this implementation, click is triggered for the entire row ( when clicked on any column )
I have tried to see the column dataIndex or key to return the click event only when the event has happened on a specific column. But args of onRow do not have that data.
Is there a way to achieve the required behavior?
If I understand correctly you want to create a table with editable row. I would suggest to create a new column (e.g. Actions) in which you will have a button that when you click it, it will let you edit the row you want. Check the following link, hope it's what you are looking for:
https://codesandbox.io/s/editable-rows-antd-4-20-6-forked-hvul4u?file=/demo.js
If you are looking to capture click events for a specific column, you can use the onCell property for column. (Codesandbox)
const columns = [
{
title: "Name",
dataIndex: "name",
render: (text, row, index) => <a>{text}</a>,
onCell: (record, rowIndex) => {
return {
onClick: () => {
console.log(record, rowIndex);
}
};
}
},
...
]

How to pass row data to a child component created into a format function

I have a react-bootstrap table with column defined like this:
const columns = [
...
{
dataField: "d",
text: "Actions",
formatter: actionFormatter,
headerAlign: "center",
},
];
The formatter function looks like this:
const actionFormatter = (cell, row) => {
return (
<div className="action-cell text-center">
<Tooltip title="View file">
<span className="svg-icon svg-icon-xl" onClick={setSelectRow}>
<SVG
src={toAbsoluteUrl("/media/svg/icons/General/Binocular.svg")}
/>
</span>
</Tooltip>
<Tooltip title="Download file">
<span className="svg-icon svg-icon-xl">
{/* Rename file on download */}
<SVG
src={toAbsoluteUrl("/media/svg/icons/Files/Download.svg")}
onClick={setSelectRow}
/>
</span>
</Tooltip>
</div>
);
};
The first part is used to show some content in an other component. I needed to get data to the parent component. But the problem is that the formatter is created once and only once at the component creation, it has no idea about any event or changes happening to row. I already struggled to do this but finished by getting it done by doing something like this:
const rowEvents = {
onClick: (e, row, rowIndex) => {
setSelectedRow(row);
setSelectedRowIsReady(true);
},
};
So, this method allow me to get the selected row by a click event on the row,
then,
const setSelectRow = useCallback(() => {
if (selectedRowIsReady) {
props.onSelectSetting(selectedRow);
}
}, [props, selectedRow, selectedRowIsReady]);
useEffect(() => {
setSelectRow();
}, [setSelectRow]);
the setSelectRow function allow me to send my row to the parent components, I had to put it in a useEffect hook because the onClick function was called before the rowEvents.
So... not very clean but at least working as expected.
Now, what I want do to is replace my formatter to look like this:
<div className="action-cell text-center">
<Tooltip title="View file">
<span className="svg-icon svg-icon-xl" onClick={setSelectRow}>
<SVG
src={toAbsoluteUrl("/media/svg/icons/General/Binocular.svg")}
/>
</span>
</Tooltip>
<SystemFileDownload row={selectedRow} />
</div>
However I do not know how to get my row into my child component because, when onClick is called, the state isn't already set. I thought about setting my selected row into my redux store but it feels kind of overkill for what I am trying to achieve.
How could I simply pass my current row to my child component ?
I tried to add my state to formatExtraData like this:
{
dataField: "d",
text: "Actions",
formatter: actionFormatter,
headerAlign: "center",
formatExtraData: selectedRow,
},
and then use selectedRow onto my props, but my child component got the row that was click on the previous click and not on the current click.
So I tried to set my row into my redux. Obviously I got the same problem, the onclick function is triggered before the rowEvents function.
So I added this to my child component:
useEffect(
(
downloadFileHandler = () => {
console.log("Download");
// Will get the data from the API
const fake_data = '{"hello": "no"}';
console.log(selectedConf);
console.log(systemName);
const fileName = ``;
}
) => {
if (firstUpdate.current) {
firstUpdate.current = false;
return;
}
downloadFileHandler();
},
[selectedConf]
);
Where I get selectedConf from my redux store, and it is set on click on a row.
But then, when I click on my download button, the useEffect hook get triggered as many time as my child component exists on the page, even if it's not part of the BootstrapTable I am working on, so not good, I do not know how to avoid this.
I feel like I am missing something obvious because my use case is like very common and simple and I have to use hooks and redux to achieve it instead of a simple props and it isn't even working.

row action based on row data in react material-table

I need to have a row action only in certain rows (with particular property values). For example, if I have a row that has the property isDeletable set to true, I would like to be able to delete it, i.e have a delete icon present in the actions column.
Thanks in advance!
In actions definitions of your MaterialTable component, you can access to rowData parameter which you can be used to conditionally calculate the disabled or hidden props of each action. Check the following example where the action enabled only when status ==='active'.
<MaterialTable
// ..other props
actions={[
(rowData) => {
return {
icon: "bug_report",
tooltip: "Report bug",
disabled: rowData.status === "active",
// hidden: rowData.status === "active",
onClick: (event, rowData) =>
alert("This client status is " + rowData.status)
};
}
]}
/>
Here is a sandbox whit a working example.
Let me know if that worked for you!

Close detail panel and open another on material-table

I am displaying a table in the detail panel of another table using material-table. I want to close or remove the existing detail panel on clicking another row data expand icon and open the detail panel of that particular row. This is the codesandbox link im working on https://codesandbox.io/s/material-demo-forked-8zy6z?file=/demo.js:0-2696.
Note: I want to close first and then need to open the other row data detail panel
you can do it with useState
const [activePanel, setActivePanel] = React.useState(null)
now onClick of row you can do something like this
onClick={() => setActivePanel(item._id)}
now you know what is active item
{activePanel && <>your jsx code goes here</>}
You can use tableRef and change the dataManager detail panel type from multiple to single.
import {useRef } from "react";
const tableRef = useRef(0);
<MaterialTable
tableRef={tableRef}
detailPanel={(rowData) => {
if (tableRef.current.dataManager !== null) {
tableRef.current.dataManager.detailPanelType = "single";
}
return (
//your Table here
);
}}
/>
you can do this by adding the following prop in options prop of material-table
detailPanelType: "single",
e.g:
options:{{
detailPanelType: "single",
}}

how to put a custom button tag in rows, use material-table and typeScript, and what are the props he expects to receive?

i have some questions :)
i try to put an Avatar tag in every row in my table and edit Button, and its take the edit button to both.
How can I move an action to the right side of the table?
How do I undo the title of "Actions" at the top of the table?
And what exactly "PROPS" should I pass if I use TS in the following example:
<MaterialTable
icons={tableIcons}
columns={this.state.columns}
data={this.state.data}
title='Users Management'
actions={[
{
icon: 'edit',
tooltip: 'Edit User',
onClick: (event) => { alert('Edit!!'); },
},
{
icon: 'avatar',
tooltip: 'Avatar User',
onClick: (event) => { alert("You want to delete "); }
}
]}
components={{
Action: **props** => (
<Button
onClick={(event: any) => props.action.onClick}>
EDIT
</Button>
),
}}
/>
enter image description here
So lets split this question into parts:
How do I undo the title of "Actions" at the top of the table? You can simply override the localization={{header.actions: 'Test'}} prop to change the action column title to change it e.g. to Test. You can also add a white space to hide it.
How can I move an action to the right side of the table? You can override options={{actionsColumnIndex: 1}} to e.g. move it to the second position or set it to -1 to move it to the end of all columns.
its take the edit button to both. Since you do not provide custom elements, it renders a text. You have to import icons={tableIcons} as written in the readme. To show an avatar icon, simply add avatars object to your tableIcons object.
To know which props to pass, look at this docs page.

Resources