I am trying to implement react table with just one row selectable at at time. I have gone through a lot of examples for multiple rows selection in a react table but in my case, the user can select only one row when the user clicks on the radio button but currently all the rows can be selected. Could anyone help me out on this to implement ?
I know this is an old question, but maybe someone will find this solution useful. Since version 7, react-table provides a stateReducer
that can be used to track and change the state of a table. (before v7 it had reducerHandlers
, but I didn't go deep into that). You can modify the state as follows:
useTable(
{
columns,
data,
stateReducer: (newState, action) => {
if (action.type === "toggleRowSelected") {
newState.selectedRowIds = {
[action.id]: true
}
}
return newState;
},
}
...
Here is the CodeSandbox with the changes described
Using react-table 7.5.0, I've put together a CodeSandbox with a react-table that functionally makes only one row selectable at a time.
In essence, I replaced an unconditionally rendered checkbox:
Cell: ({ row }) => (
<div>
<IndeterminateCheckbox {...row.getToggleRowSelectedProps()} />
</div>
)
with a conditionally rendered checkbox:
Cell: ({ row }) => {
if (
rows.filter((row) => row.isSelected).length < 1 ||
row.isSelected
) {
return (
<div>
<IndeterminateCheckbox {...row.getToggleRowSelectedProps()} />
</div>
);
} else {
return (
<div>
<IndeterminateCheckbox
checked={false}
readOnly
style={row.getToggleRowSelectedProps().style}
/>
</div>
);
}
}
I filtered all row objects to check for selected rows and then I conditionally rendered a normally functioning react-table checkbox if the number of selected rows is less than 1 or if the row is already selected.
If the number of checked rows is at least one and the row isn't selected, I render a read only checkbox that can't be selected.
Ideally, I would have liked to use react-table's built-in selectedRowIds instead of filtering through all row objects, but I couldn't figure out how to implement useTable() in a manner that allows me to refer to it since it is derived from it.
Here is react-table's Row Selection CodeSandbox that I forked from. Here's the relevant page in their docs.
I'll move the code into a built-in code snippet at a later time.
Cell: ({row}) => (
<IndeterminateCheckbox
{...row.getToggleRowSelectedProps({
onChange: () => {
const selected = row.isSelected; // get selected status of current row.
toggleAllRowsSelected(false); // deselect all.
row.toggleRowSelected(!selected); // reverse selected status of current row.
},
})}
/>
)
For me cleaning selected rows before select a new one worked. Version: "@tanstack/react-table": "^8.7.4"
,
Cell: ({ row, table }) => (
<IndeterminateCheckbox
{...row.getToggleRowSelectedProps({
onChange: () => {
table.resetRowSelection()
row.toggleSelected()
},
})}
/>
)
I've notice that @Ann answers works great with minor issue - if you want to toggle off selected row, it won't work.
I've added a validation to fix this:
useTable(
{
columns,
data,
stateReducer: (state, action) => {
if (action.type === 'toggleRowSelected' && Object.keys(state.selectedRowIds).length) {
const newState = { ...state };
newState.selectedRowIds = {
[action.id]: true,
};
return newState;
}
return state;
},
}
...
)
This is an old one, but here is my solution:
Get toggleAllRowsSelected from table instance.
const {
allColumns,
getTableBodyProps,
getTableProps,
headerGroups,
prepareRow,
rows,
state,
toggleAllRowsSelected,
} = useTable(
{
columns,
data,
},
useRowSelect
);
Then add onClick like in code below to your tr-component (in my code tr has been styled with emotion and named StyledTableRow). This will first set all selected rows to false and then toggle current row isSelected value if it was false initially, if it was true then it has already been set to false.
If you don't want to allow clicking selected row to unselect it (eg. for radio buttons), just use the isSelected === true to block any action here.
{rows.map((row, i) => {
prepareRow(row);
// const isRowSelected = isSelected(row.id);
const { isSelected, getRowProps, getToggleRowSelectedProps, toggleRowSelected } = row;
const {
onChange,
indeterminate,
...toggleRowSelectedProps
} = getToggleRowSelectedProps();
console.log(row);
return (
<StyledTableRow
hover
{...getRowProps()}
{...toggleRowSelectedProps}
selected={isSelected}
onClick={() => {
const current = isSelected;
toggleAllRowsSelected(false);
if (!current) {
toggleRowSelected();
}
}}
>
{row.cells.map((cell, key) => (
On TanStack Table v8, for me the easiest approach was to adjust the onRowSelectionChange
parameter of useReactTable
.
I just updated it to reset the local rowSelection
state to an empty object first:
const table = useReactTable({
columns,
data: tableData,
state: {
rowSelection,
},
enableRowSelection: true,
onRowSelectionChange: stateUpdater => {
setRowSelection({}); // <-- First reset the current selection
setRowSelection(stateUpdater);
},
getCoreRowModel: getCoreRowModel(),
});
Here is a sandbox as well:
https://codesandbox.io/s/divine-shadow-9sw2xm?file=/src/App.js
This is a simple react implementation of "radio-like" behaviour with useReducer
to demonstrate how to use state management with table.
const { useReducer } = React; // --> for inline use
// import React, { useReducer } from 'react'; // --> for real project
const reducer = (state, action) => {
return { checkedId: action.id }
}
const App = () => {
const [state, dispatch] = useReducer(reducer, {})
const CheckBox = ({id}) => (
<input
id={id}
onClick={() => dispatch({ id })}
checked={state.checkedId === id}
type="checkbox"
/>
)
return (
<table border="1">
<tr><td><CheckBox id="1" /></td><td>John</td></tr>
<tr><td><CheckBox id="2" /></td><td>Doe</td></tr>
</table>
)
};
ReactDOM.render(<App />, document.getElementById('root'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.9.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.9.0/umd/react-dom.production.min.js"></script>
<div id="root"></div>
You can also override the onChange method on the Cell(...) prop function.
https://react-table.tanstack.com/docs/api/useRowSelect#row-properties
getToggleRowSelectedProps: Function(props) => props Use this function to get the props needed for a select row checkbox. Props: onChange: Function() style.cursor: 'pointer' checked: Bool title: 'Toggle Row Selected'
I'll give a sandbox later when I have the extra time.
© 2022 - 2024 — McMap. All rights reserved.