7

does anyone know a way to select multiple rows with React-Table. Say if we wish to click a cell in a row and then press SHIFT and then select another row and perhaps color code the selected rows with CSS? Is this even possible?

1
  • 1
    Did you find a solution? Commented May 8, 2019 at 14:53

2 Answers 2

12

I found a way to do it. Let me know if you have any questions. Basically just need to implement on your own.

   state = {
    selected: null,
    selectedRows: [],
  }

  previousRow = null;

  handleClick = (state, rowInfo) => {
    if (rowInfo) {
      return {
        onClick: (e) => {
          let selectedRows = [];
          // if shift key is being pressed upon click and there is a row that was previously selected, grab all rows inbetween including both previous and current clicked rows
          if (e.shiftKey && this.previousRow) {
            // if previous row is above current row in table
            if (this.previousRow.index < rowInfo.index) {
              for (let i = this.previousRow.index; i <= rowInfo.index; i++) {
                selectedRows.push(state.sortedData[i]);
              }
            // or the opposite
            } else {
              for (let i = rowInfo.index; i <= this.previousRow.index; i++) {
                selectedRows.push(state.sortedData[i]);
              }
            }
          } else {
            // add _index field so this entry is same as others from sortedData
            rowInfo._index = rowInfo.index;
            selectedRows.push(rowInfo);
            this.previousRow = rowInfo;
          }
          this.setState({ selected: rowInfo.index, selectedRows })
        },
        style: {
          // check index of rows in selectedRows against all rowInfo's indices, to match them up, and return true/highlight row, if there is a index from selectedRows in rowInfo/the table data
          background: this.state.selectedRows.some((e) => e._index === rowInfo.index) && '#9bdfff',
        }
      }
    } else {
      return {}
    }
Sign up to request clarification or add additional context in comments.

2 Comments

I do not understand the line rowInfo._index = rowInfo.index;
This was a while ago but if I remember correctly it was because sortedData used _index instead of index
0

I built this out with react-table 6.x. I'm using the checkbox table HOC. My enclosing component is a functional component using hooks. It handles shift-click in both directions (top to bottom, bottom to top) and handles shift-unselect.

Basic component setup:

import checkboxHOC from 'react-table/lib/hoc/selectTable'
// see "selectTable" - https://github.com/TanStack/table/blob/v6.8.6/src/hoc/README.md
const CheckboxTable = checkboxHOC(ReactTable)
const TableElement = CheckboxTable

const selection = .... // some array of primary keys

const [lastPrimaryKeySelected, setLastPrimaryKeySelected] = React.useState(null)

return <TableElement toggleSelection={toggleSelection} ... />

Then the biz logic:

  const toggleSelection = React.useCallback(
    (id, e) => {
      const currentlyChecking = !selection.has(id)
      const previouslyChecking = selection.has(lastPrimaryKeySelected)

      if (e.shiftKey && lastPrimaryKeySelected && previouslyChecking === currentlyChecking) {
        // Support shift-click. (Check all locations from lastPrimaryKeySelected to id)
        // This ^ also avoids doing anything if they select a box then shift-unselect another box.

        toggleRange(lastPrimaryKeySelected, id, currentlyChecking)
      } else {
        toggleRange(id, id, currentlyChecking)
      }

      setLastPrimaryKeySelected(id)
    },
    [selection, lastPrimaryKeySelected, toggleRange]
  )

  // Unconditionally check or uncheck the range.
  // checkRange - when false, this will uncheck the range.
  // primaryKeyA / primaryKeyB - the order isn't important.
  const toggleRange = React.useCallback(
    (primaryKeyA, primaryKeyB, checkRange) => {
      const setCopy = new Set(selection)

      // keys are primary keys of some record
      // values are the index of internalData
      const primaryKeyToIndex = {}

      // Seems sketchy but the official examples demonstrate this: https://github.com/TanStack/table/blob/v6.8.6/docs/src/examples/selecttable/index.js#L104-L111
      // https://stackoverflow.com/a/52986052
      const internalData = reactTable.current.getWrappedInstance().getResolvedState().sortedData
      internalData?.forEach((d, index) => {
        primaryKeyToIndex[d._original.id] = index
      })
      // potential (but complicated) optimization here ^: only fill out primaryKeyToIndex for the current page being viewed.
      // It currently holds the entire list of records
      // Complicated because react-table doesn't seem to expose the current page worth of data, so we'd have to calculate offsets ourselves.

      // `sort` makes the following for-loop simpler. Handles shift-clicking from top to bottom, or bottom to top.
      const [startIndex, endIndex] = [primaryKeyToIndex[primaryKeyA], primaryKeyToIndex[primaryKeyB]].sort(
        (a, b) => a - b // JS can't sort numbers correctly without a comparator function
      )

      for (let i = startIndex; i <= endIndex; i += 1) {
        const primaryKeyForIndex = internalData[i]._original.id

        if (checkRange) {
          setCopy.add(primaryKeyForIndex) // handle shift-select
        } else {
          setCopy.delete(primaryKeyForIndex) // handle shift-unselect
        }
      }

      onSelectionChange(setCopy)
    },
    [onSelectionChange, selection]
  )

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.