I have a simple react table where I would like the name
cell to be editable only when I click on the button inside the cell
Default settings:
const columns = React.useMemo(
() => [
{
Header: 'ID',
accessor: 'id'
},
{
Header: 'Name',
accessor: 'name'
},
],
[]
)
How it renders with default settings:
Updated column configuration
const columns = React.useMemo(
() => [
{
Header: 'ID',
accessor: 'id'
},
{
Header: 'Name',
accessor: 'name',
Cell: (cellObj) => <div>{cellObj.value}<button onClick={() => handleClickEditRow(cellObj.row.index, 'name', cellObj.value)}>Edit</button></div>
},
],
[]
)
Click Handler
const handleClickEditRow = (rowIndex, columnId, value) => {
setData(old =>
old.map((row, index) => {
if (index === rowIndex) {
return {
...old[rowIndex],
[columnId]: value,
isEditing: true
}
}
return row
})
)
}
With updated configuration I do see the button but the problem is the onClick
calls the handler but doesn't put the cell in edit mode
Here is the rest of the code
Table:
export function Table({columns, data, updateMyData, skipPageReset}) {
const {
getTableProps,
getTableBodyProps,
headerGroups,
prepareRow,
page,
canPreviousPage,
canNextPage,
pageOptions,
pageCount,
gotoPage,
nextPage,
previousPage,
setPageSize,
state: {pageIndex, pageSize},
} = useTable(
{
columns,
data,
defaultColumn,
autoResetPage: !skipPageReset,
updateMyData,
},
usePagination, useRowState
)
return (
<>
<table {...getTableProps()}>
<thead>
{headerGroups.map(headerGroup => (
<tr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map(column => (
<th {...column.getHeaderProps()}>{column.render('Header')}</th>
))}
</tr>
))}
</thead>
<tbody {...getTableBodyProps()}>
{page.map((row, i) => {
prepareRow(row)
return (
<tr {...row.getRowProps()}>
{row.cells.map(cell => {
return <td {...cell.getCellProps()}>{cell.render('Cell')}</td>
})}
</tr>
)
})}
</tbody>
</table>
<div className="pagination">
<button onClick={() => gotoPage(0)} disabled={!canPreviousPage}> {'<<'} </button>
{' '}
<button onClick={() => previousPage()} disabled={!canPreviousPage}> {'<'} </button>
{' '}
<button onClick={() => nextPage()} disabled={!canNextPage}> {'>'} </button>
{' '}
<button onClick={() => gotoPage(pageCount - 1)} disabled={!canNextPage}> {'>>'} </button>
{' '}
<span>
Page{' '}
<strong>
{pageIndex + 1} of {pageOptions.length}
</strong>{' '}
</span>
<span>
| Go to page:{' '}
<input type="number" defaultValue={pageIndex + 1} onChange={e => {const page = e.target.value ? Number(e.target.value) - 1 : 0 gotoPage(page)}}style={{width: '100px'}}/>
</span>{' '}
<select value={pageSize} onChange={e => {setPageSize(Number(e.target.value))}}>
{[10, 20, 30, 40, 50].map(pageSize => (
<option key={pageSize} value={pageSize}>
Show {pageSize}
</option>
))}
</select>
</div>
</>
)
}
Editable Cell:
const EditableCell = ({
value: initialValue,
row: {index},
column: {id},
isEditing,
updateMyData,
}) => {
const [value, setValue] = React.useState(initialValue)
const onChange = e => {
setValue(e.target.value)
}
const onBlur = () => {
updateMyData(index, id, value)
}
React.useEffect(() => {
setValue(initialValue)
}, [initialValue])
let retObj = null;
if (id === 'id') {
retObj = <div>{value}</div>
} else if (id === 'name' && isEditing) {
retObj = <input value={value} onChange={onChange} onBlur={onBlur}/>
} else {
retObj = <input value={value} onChange={onChange} onBlur={onBlur}/>
}
return retObj;
}
I have gone through a lot of forums and questions but haven't had any luck. This particular question came really close to what I was trying to achieve but I followed the answer with no luck: Similar Question
I am also new to React so please let me know if there is more information that I need to post.
I would really appreciate any help with this.