0

I am trying to add entries into an array, the entries being an object that corresponds to the row of a table. Each row is being highlighted by a color once it is selected. Multiple rows can also be selected using Ctrl Key. On each click I am pushing that row info object into the array. It is defined as a SET and same entry is being duplicated when the same row is clicked multiple times. Also I am unable to de-select the one's that are selected.I am using react-table for the data-grid purposes. Can some one help me out here? Help would be really appreciated.

Sandbox: https://codesandbox.io/s/react-table-row-table-final-hor8j

import * as React from "react";
import ReactTable from "react-table";

export default class DataGrid extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      selectedRows: []
    };
  }

  rowClick = (state, rowInfo) => {
    if (rowInfo) {
      let selectedRows = new Set();
      return {
        onClick: e => {
          if (e.ctrlKey) {
            selectedRows = this.state.selectedRows;
            rowInfo._index = rowInfo.index;
            selectedRows.push(rowInfo);
            this.setState({
              selectedRows
            });
          } else {
            selectedRows = [];
            rowInfo._index = rowInfo.index;
            selectedRows.push(rowInfo);
          }
          this.setState(
            {
              selectedRows
            },
            () => {
              console.log("final values", this.state.selectedRows);
              this.props.rowClicked(this.state.selectedRows);
            }
          );
        },
        style: {
          background:
            this.state.selectedRows.some(e => e._index === rowInfo.index) &&
            "#9bdfff"
        }
      };
    } else {
      return "";
    }
  };

  render() {
    return (
      <ReactTable
        data={this.props.data}
        columns={this.props.columns}
        getTrProps={this.rowClick}
      />
    );
  }
}
Misha Akopov
  • 12,241
  • 27
  • 68
  • 82
joy08
  • 9,004
  • 8
  • 38
  • 73
  • 2
    `Even though its defined as a SET, still it has duplicates when the same row is clicked multiple times` This happens because even if the object might have the same properties, it's different reference to an object. If you do `new Set([{}, {}])` you will see that it have size of 2. – Vencovsky Dec 16 '19 at 15:16
  • 1
    You define selectedRows here: ` let selectedRows = new Set();` -- but you replace the value of selectedRows every time before you use it, `selectedRows = this.state.selectedRows;` besides, a Set doesn't have a `push` function – TKoL Dec 16 '19 at 15:20
  • Does this answer your question? [Remove duplicates from an array of objects in JavaScript](https://stackoverflow.com/questions/2218999/remove-duplicates-from-an-array-of-objects-in-javascript) – Emile Bergeron Dec 16 '19 at 15:23
  • 1
    I added a solution using a `Set` (which is a great idea) and allows you to select and unselect multiple rows. – Brett DeWoody Dec 16 '19 at 17:08
  • @Brett DeWoody wanted something in terms of react table. Like the one in the sandbox. Thanks anyways :) – joy08 Dec 16 '19 at 17:21
  • 1
    Ah, got it, I thought the question was more around how to use `Set`. – Brett DeWoody Dec 16 '19 at 17:37
  • @Brett DeWoody. You could still give a simplified solution if you've got one, by modifying the same sandbox :) – joy08 Dec 16 '19 at 17:46

3 Answers3

2

You have defined selectedRows as an empty Set but then quickly replaced it with an array this.state.selectedRows. Every operation done post this would be done on the array instead of the set.

Here is an example of how you can make changes to your code to use a set instead:

const selectedRows = new Set(this.state.selectedRows); // Initialise the set with the items from your array. 
...
selectedRows.add(rowInfo); // Similar to an array push

You can find more on how the JS Set works at https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set.

Pranjal Nadhani
  • 106
  • 1
  • 5
1

Here is an updated sandbox to avoid duplicates https://codesandbox.io/s/react-table-row-table-alternate-single-row-working-1itsy

The solution includes unselecting rows on second click.

Happy coding:)

kooskoos
  • 4,622
  • 1
  • 12
  • 29
1

Here's a simplified demo using a functional component and Set to manage the selected rows. It allows rows to be selected and unselected.

This functional component could be changed to extend React.Component using a similar setup.

const App = ({data}) => {

  const [selected, setSelected] = React.useState(new Set());

  const handleClick = (row) => {
    const updatedSelected = new Set(selected);
    
    if (updatedSelected.has(row)) {
      updatedSelected.delete(row);
    } else {
      updatedSelected.add(row);
    }
    
    setSelected(updatedSelected);
  }
  
  React.useEffect(() => {
    console.log(Array.from(selected));
  });

  return (
    <table>
      <thead>
        <tr>
          <th>ID</th>
          <th>Name</th>
        </tr>
      </thead>
      <tbody>
      {data.map(row => (
        <tr onClick={() => handleClick(row)} className={selected.has(row) && 'selected'}>
          <td>{row.id}</td>
          <td>{row.text}</td>
        </tr>
      ))}
      </tbody>
    </table>
  )
}

const data = [
  {id: 0, text: 0},
  {id: 1, text: 1},
  {id: 2, text: 2},
  {id: 3, text: 3},
  {id: 4, text: 4},
  {id: 5, text: 5},
  {id: 6, text: 6},
  {id: 7, text: 7},
  {id: 8, text: 8}
]


ReactDOM.render(<App data={data} />, document.getElementById('root'))
.selected {
  background-color: lightgreen;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.11.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.11.0/umd/react-dom.production.min.js"></script>

<div id="root"></div>
Brett DeWoody
  • 59,771
  • 29
  • 135
  • 184