1

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:

Table 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.

Nick Div
  • 5,338
  • 12
  • 65
  • 127

0 Answers0