4
votes

I'm having trouble adding checkboxes to rows using this react-table package https://react-table.js.org/#/story/readme

I'm trying to add a checkbox to each row in my table. I tried adding "checkbox" to the "Cell" value seen in the columns area, however, it seems that it doesn't work well with the pagination. Once I click next page and then back it forgets all of the previously checked products. How do I maintain their state?

I added a key, and it prevents the element from being checked on all pages, however, it doesn't remember it when I change back and forth on the pages. So I just need to store its "on state" now.

Cell: rowInfo => (<Checkbox key={rowInfo.index} onChange={this.handleChange} />)

Here's the full code:

import React from 'react'
import ReactDOM from 'react-dom'
import ReactTable from 'react-table'
import PropTypes from 'prop-types'
import { Checkbox } from '@shopify/polaris';

export default class ProductIndexTable extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
     rowInfo: '' 
    }
    this.handleChange = this.handleChange.bind(this)
  }
  handleChange(event) {
  }
  render() {
    function CreateItem(product) {
      return { 
        title: <a href={'/products/' + product.id} >{product.title}</a>,
        price_test_status: product.has_active_price_test,
        price_test_completion_percentage: product.price_test_completion_percentage
      }
    }
  return (<ReactTable
            data={this.props.products.map(CreateItem)}
            getTdProps={(state, rowInfo, column, instance) => {
              return {
                onClick: (e, handleOriginal) => {
                  // console.log('A Td Element was clicked!')
                  // console.log('it produced this event:', e)
                  // console.log('It was in this column:', column)
                  // console.log('It was in this row:', rowInfo)
                  // console.log('It was in this table instance:', instance)
                  this.setState({
                    rowInfo: rowInfo.index
                  })
                  // IMPORTANT! React-Table uses onClick internally to trigger
                  // events like expanding SubComponents and pivots.
                  // By default a custom 'onClick' handler will override this functionality.
                  // If you want to fire the original onClick handler, call the
                  // 'handleOriginal' function.
                  if (handleOriginal) {
                    handleOriginal()
                  }
                }
              }
            }}
            columns={[
            {
              Header: "Base",
              columns: [
                {
                  Header: <Checkbox />,
                  maxWidth: 50,
                  Cell: (<Checkbox onChange={this.handleChange} />)
                }, {
                  Header: "Product Title",
                  accessor: "title",
                  maxWidth: 400
                }, {
                  Header: "Price Test Status",
                  accessor: "price_test_status",
                  maxWidth: 200
                }, {
                  Header: "Price Test Completion Percentage",
                  accessor: "price_test_completion_percentage",
                  Cell: row => (
                    <div
                      style={{
                        width: '100%',
                        height: '100%',
                        backgroundColor: '#dadada',
                        borderRadius: '2px'
                      }}
                    >
                    <div
                      style={{
                        width: `${row.value}%`,
                        height: '100%',
                        backgroundColor: row.value > 66 ? '#85cc00'
                          : row.value > 33 ? '#ffbf00'
                          : '#ff2e00',
                        borderRadius: '2px',
                        transition: 'all .2s ease-out'
                      }}
                    />
                    </div>
                  )
                }
              ]
            }
            ]}
            defaultPageSize={10}
            className="-striped -highlight"
          />
  );}
}
2
have you tried using a key prop on the checkboxes? - Carlos A. Jimenez Holmquist
You could try raising an issue here: github.com/react-tools/react-table/issues as this sounds like a bug in the package - Mikkel
Good idea. Just raised the issue. I'm still wondering if there's a workaround for it though? I haven't tried using a key prop. I'm new to react, so I'll have to do some research on it. - ByteMe
@ByteMe just add the key prop and put a unique id, it can be the counter from the map function. React uses this to difference same components when they're all in the Virtual DOM - Carlos A. Jimenez Holmquist
Thanks Carlos, I added the key prop and it prevents it from checking all the elements on the other pages. I just need to figure out how to store them now. See my update - ByteMe

2 Answers

7
votes

I ended up storing the titles into a hash when clicked and that gave me my final solution. It checks the hash state to see if the value is true and should remain checked. See code below. Hope it helps others! Also check the codepen example I used to help me.

https://codepen.io/aaronschwartz/pen/WOOPRw?editors=0010

import React from 'react'
import ReactDOM from 'react-dom'
import ReactTable from 'react-table'
import PropTypes from 'prop-types'
import { Checkbox } from '@shopify/polaris';

export default class ProductIndexTable extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
     selected: {},
     selectAll: 0,
     products: this.props.products
    }
    this.toggleRow = this.toggleRow.bind(this);
  }
    toggleRow(title) {
        const newSelected = Object.assign({}, this.state.selected);
        newSelected[title] = !this.state.selected[title];
        this.setState({
            selected: newSelected,
            selectAll: 2
        });
    }
    toggleSelectAll() {
        let newSelected = {};
        if (this.state.selectAll === 0) {
            this.state.products.forEach(x => {
                newSelected[x.title] = true;
            });
        }
        this.setState({
            selected: newSelected,
            selectAll: this.state.selectAll === 0 ? 1 : 0
        });
    }

  render() {
    function CreateItem(product) {
      return { 
        title: <a href={'/products/' + product.id} >{product.title}</a>,
        price_test_status: product.has_active_price_test,
        price_test_completion_percentage: product.price_test_completion_percentage
      }
    }
  return (<ReactTable
            data={this.props.products.map(CreateItem)}
            columns={[
            {
              Header: "Base",
              columns: [
                {
                            id: "checkbox",
                            accessor: "",
                            Cell: ( rowInfo ) => {
                                return (
                                    <Checkbox
                                        type="checkbox"
                                        className="checkbox"
                                      checked={this.state.selected[rowInfo.original.title.props.children] === true}
                                        onChange={() => this.toggleRow(rowInfo.original.title.props.children)}
                                    />
                                );
                            },
                            Header: title => {
                                return (
                                    <Checkbox
                                        type="checkbox"
                                        className="checkbox"
                                        checked={this.state.selectAll === 1}
                                        ref={input => {
                                            if (input) {
                                                input.indeterminate = this.state.selectAll === 2;
                                            }
                                        }}
                                        onChange={() => this.toggleSelectAll()}
                                    />
                                );
                            },
                            sortable: false,
                            width: 45
                        },                
                {
                  Header: "Product Title",
                  accessor: "title",
                  maxWidth: 400
                }, {
                  Header: "Price Test Status",
                  accessor: "price_test_status",
                  maxWidth: 200
                }, {
                  Header: "Price Test Completion Percentage",
                  accessor: "price_test_completion_percentage",
                  Cell: row => (
                    <div
                      style={{
                        width: '100%',
                        height: '100%',
                        backgroundColor: '#dadada',
                        borderRadius: '2px'
                      }}
                    >
                    <div
                      style={{
                        width: `${row.value}%`,
                        height: '100%',
                        backgroundColor: row.value > 66 ? '#85cc00'
                          : row.value > 33 ? '#ffbf00'
                          : '#ff2e00',
                        borderRadius: '2px',
                        transition: 'all .2s ease-out'
                      }}
                    />
                    </div>
                  )
                }
              ]
            }
            ]}
            defaultPageSize={10}
            className="-striped -highlight"
          />
  );}
}
0
votes

To solve the problem of checking the items in all the pages, just add the key prop on the <Checkbox /> components.

Now, with the problem of storing the state, how many checkboxes are we talking about? You should have an array in your state, with all the checkboxes, and once a checkbox is checked you could send the ID (key props, which could be the counter on the .map()) and set that position of the array as true or false (checked or unchecked)