Indeterminate checkbox not working when filtered React MUI-Datatables

2k Views Asked by At

Info

I have a project that is using React, Redux, and MUI-Datatables. A simple demo for this project can be found at this CodeSandbox.

In this app, there are two main components, a map and a datatable. The two communicate via redux so that when a row is selected in the table, the respective circle in the map is highlighted and vice versa.

Problem

My problem is with the indeterminate toggle selectAll checkbox on the table. When the user has selected a row then applies a filter, the selectAll checkbox shows the '-' indeterminate symbol, but nothing happens when it is clicked.

Steps to recreate:

  • User selects the first row in the table, circle1.
  • User opens filter dialog in right-hand corner of table.
  • From the Marker dropdown menu in the filter dialog, User selects circle3 as the filter value.
  • User closes filter dialog
  • User clicks on selectAll checkbox at the top of the select row column. It will be showing the '-' symbol.
  • Notice that nothing changes. No rows are selected or deselected.

Desired Behavior:

When the User has selected a row in the table then applies a filter, the selectAll checkbox should still select all visible rows on first click and deselect all on second click the same way it normally would.

Code

Live: CodeSandbox

Table Component:

import React, { useEffect, useState } from "react";
import MUIDataTable from "mui-datatables";

import { connect } from "react-redux";

import { handleSelection } from "./redux";

import circles from "./assets/data/circles";

import { addToOrRemoveFromArray } from "./utils";

// Table component
const Table = ({ handleSelection, selections }) => {
  const [selectionIndexes, setSelectionIndexes] = useState([]);

  // When 'selections' changes in redux store:
  useEffect(() => {
    let indexes = [];
    // Iterate selections:
    selections.forEach((selection) => {
      // Push the index of the selected
      // circle into index arr:
      let index = circles.indexOf(selection);
      indexes.push(index);
    });
    // Set selections to local state hook:
    setSelectionIndexes(indexes);
  }, [selections]);

  // Table options:
  const options = {
    rowsSelected: selectionIndexes, // User provided array of numbers (dataIndexes) which indicates the selected rows
    selectToolbarPlacement: "none",
    selectableRows: "multiple", // Enable selection of multiple rows
    setRowProps: (row, dataIndex, rowIndex) => {
      return {
        style: {
          padding: ".5rem",
          margin: ".5rem auto"
        }
      };
    },
    // When a row(s) is/are selected:
    onRowSelectionChange: (
      currentRowsSelected,
      allRowsSelected,
      rowsSelected
    ) => {
      let temp = [];
      let indexes = [];
      // Iterate rowsSelected:
      rowsSelected.forEach((row) => {
        // Add or remove row index to/from indexes arr:
        indexes = addToOrRemoveFromArray(row, indexes, "indexes");
        // Circle data:
        let circle_data = circles[row];
        // Add or remove circle_data to/from temp arr:
        temp = addToOrRemoveFromArray(circle_data, temp, "temp");
      });
      // Set indexes to local hook:
      setSelectionIndexes(indexes);
      // Send the circle data to redux:
      handleSelection(temp);
    }
  };

  const columns = [
    {
      name: "marker",
      label: "Marker",
      options: {
        filter: true,
        sort: false
      }
    },
    {
      name: "lat",
      label: "Latitude",
      options: {
        filter: true,
        sort: false
      }
    },
    {
      name: "lon",
      label: "Longitude",
      options: {
        filter: true,
        sort: false
      }
    },
    {
      name: "radius",
      label: "Radius",
      options: {
        filter: true,
        sort: false
      }
    }
  ];

  const table_name = `Circle Markers`;

  return (
    <>
      <div style={{ display: "table", tableLayout: "fixed", width: "100%" }}>
        <MUIDataTable
          title={<h3>{table_name}</h3>}
          data={circles}
          columns={columns}
          options={options}
        />
      </div>
    </>
  );
};

const mapStateToProps = (state) => {
  return {
    selections: state.selection.selections
  };
};

const mapDispatchToProps = (dispatch) => {
  return {
    handleSelection: (selections) => dispatch(handleSelection(selections))
  };
};

export default connect(mapStateToProps, mapDispatchToProps)(Table);

How can I get the selectAll checkbox to work properly when a row outside of the filtered data has been selected?

1

There are 1 best solutions below

2
On

Is it ok to de-select the selected row when filters applied? I did a workaround to meet the desired behavior.

Live Code: CodeSandBox

I added additional code in Table.jsx line 34

onFilterChange: (changedColumn, changedColumnIndex, displayData) => {
  changedColumnIndex.forEach((data, key) => {
    if (Array.isArray(data) && data.length) {
      setSelectionIndexes([]);
    }
  });
},