EDIT : This issue also concerns Material Ui's Data table. I tried using the same example as given by the documentation but the same problem occurs.
I have been battling with an issue regarding the provided selection feature where, when I click on a select, the box ripples, but does not get selected (no checkmark). The weird thing is that when I tried to create a code sandbox using the same components, everything worked just fine. I'm unsure how to debug this, but it seems that the environment is the cause.
I have forked the material-table-core/core project, and I am planning to do some debugging on there, but don't necessarily know where to look. Thought maybe some bored soul could offer some guidance here ?
It should be noted that if I try to control the checked state from "outside" of the table like instructed in this issue, the selection works just fine.
Here is a gif of the behavior :
The website is a PHP/contao legacy app on a Linux remote server with a lot of jquery all over the place, we recently decided to start using react and deprecating our jquery code gradually. I am currently using a fork of @material-table/[email protected]. But no changes to the fork have been made yet. I just want to use it as a debugging tool. As you can assume, react/webpack and babel have been manually installed and configured (not using CRA).
To understand how react is loaded, take a look at the following files (stripped of all irrelevant code for clarity) :
Index.html5 : (most of these script tags are needed for the old legacy app)
<!DOCTYPE html>
<html>
<head>
<link rel="preconnect" href="https://fonts.gstatic.com">
<link href="https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,300;0,400;0,600;0,700;0,800;1,300;1,400;1,600;1,700;1,800&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Material+Icons|Material+Icons+Outlined|Material+Icons+Two+Tone|Material+Icons+Round|Material+Icons+Sharp" rel="stylesheet">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js" integrity="sha512-894YE6QWD5I59HgZOGReFYm4dnWc1Qt5NtvYSaNcOP+u1T9qYdvdihz0PPSiiqn/+/3e7Jo4EaG7TubfWGUrMQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://code.jquery.com/jquery-migrate-3.3.2<?= $prodOrDevMode ?>.js"></script>
<script src="https://code.jquery.com/ui/1.13.0/jquery-ui.min.js"></script> <!-- //! upgraded -->
<script src="files/script/tag-it/js/tag-it.js" type="text/javascript" charset="utf-8"></script>
<script src="files/script/bootstrap-tagsinput/dist/bootstrap-tagsinput<?= $prodOrDevMode ?>.js" type="text/javascript" charset="utf-8"></script> <!-- //! upgraded -->
<script src="files/script/erp.js?v=<?= date('ymdh'); ?>" type="text/javascript"></script>
<script src="files/script/cms.js?v=<?= date('ymdh'); ?>" type="text/javascript"></script>
<script src="files/script/typeahead.js/dist/typeahead.bundle.js?v=<?= date('ymdh'); ?>" type="text/javascript"></script>
<script src="/files/script/dropzone.js"></script>
<script src="files/script/tinyMCE/tinymce.min.js" type="text/javascript"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js" type="text/javascript"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]"></script>
<script>Chart.plugins.unregister(ChartDataLabels);</script>
<script src="files/bootstrap/js/bootstrap.bundle.min.js" type="text/javascript"></script>
<script src="files/script/tableExport.jquery.plugin-master/tableExport.min.js"></script>
<script src="files/script/tableExport.jquery.plugin-master/libs/jsPDF/jspdf.min.js"></script>
<script src="files/script/tableExport.jquery.plugin-master/libs/jsPDF-AutoTable/jspdf.plugin.autotable.js"></script>
<script src="node_modules/bootstrap-table/dist/bootstrap-table.js" type="text/javascript"></script>
<script src="node_modules/bootstrap-table/dist/locale/bootstrap-table-it-IT.js"></script>
<script src="node_modules/bootstrap-table/dist/locale/bootstrap-table-es-ES.js"></script>
<script src="node_modules/bootstrap-table/dist/locale/bootstrap-table-fr-FR.js"></script>
<script src="node_modules/bootstrap-table/dist/locale/bootstrap-table-en-US.js"></script>
<script src="node_modules/bootstrap-table/dist/locale/bootstrap-table-de-DE.min.js"></script>
<script src="node_modules/bootstrap-table/dist/extensions/sticky-header/bootstrap-table-sticky-header.js"></script>
<script src="node_modules/bootstrap-table/dist/extensions/export/bootstrap-table-export.min.js"></script>
<script src="node_modules/bootstrap-table/dist/extensions/toolbar/bootstrap-table-toolbar.min.js"></script>
<script src="node_modules/bootstrap-table/dist/extensions/filter-control/bootstrap-table-filter-control.min.js"></script>
<script src="node_modules/bootstrap-table/dist/extensions/mobile/bootstrap-table-mobile.min.js"></script>
<script src="node_modules/bootstrap-table/dist/extensions/fixed-columns/bootstrap-table-fixed-columns.min.js"></script>
<script src="files/script/moment.js"></script>
<script src="files/script/select2/dist/js/select2.min.js"></script>
<script src="files/script/select2/dist/js/i18n/de.js"></script>
<script src="files/script/bootstrap-datetimepicker.min.js"></script>
<script src="files/script/bootstrap-colorpicker-2.5.2/dist/js/bootstrap-colorpicker.min.js"></script>
<script src="files/script/myDropzone.js"></script>
<script src="files/script/jquery.mark.min.js"></script>
<script src="files/script/bootstrap-select-1.13.14/dist/js/bootstrap-select.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.16.2/xlsx.full.min.js"></script>
<?php include_once 'dist/styles.html5'; ?> <--- css build loads here
</head>
<body id="top" >
..html/scripts
<!-- Load our Bundled js files. Unbundled files can be found in : ./react/src/Index.js -->
<?php include_once 'dist/main.html5'; ?> <--- react build loads here
</body>
</html>
Index.js :
import React, { StrictMode } from "react";
import { render } from "react-dom";
import "./Index.css";
import TimeTrackingTable from "./TimeTrackingTable";
const timeTrackingTable = document.getElementById(
"time_tracking_react_component"
);
if (timeTrackingTable) {
// console.log("timeTrackingTable", timeTrackingTable);
render(
<StrictMode>
{/* <Provider store={store}> */}
<TimeTrackingTable {...timeTrackingTable.dataset} />
{/* </Provider> */}
</StrictMode>,
timeTrackingTable
);
}
Timetracking component :
import React, { useState, forwardRef } from "react";
import MaterialTable from "@material-table/core";
import { Switch } from "@mui/material";
import {
AddBox,
ArrowUpward,
Check,
ChevronLeft,
ChevronRight,
Clear,
DeleteOutline,
Edit,
FilterList,
FirstPage,
LastPage,
Remove,
SaveAlt,
Search,
ViewColumn,
} from "@mui/icons-material";
const tableIcons = {
Add: forwardRef((props, ref) => <AddBox {...props} ref={ref} />),
Check: forwardRef((props, ref) => <Check {...props} ref={ref} />),
Clear: forwardRef((props, ref) => <Clear {...props} ref={ref} />),
Delete: forwardRef((props, ref) => <DeleteOutline {...props} ref={ref} />),
DetailPanel: forwardRef((props, ref) => (
<ChevronRight {...props} ref={ref} />
)),
Edit: forwardRef((props, ref) => <Edit {...props} ref={ref} />),
Export: forwardRef((props, ref) => <SaveAlt {...props} ref={ref} />),
Filter: forwardRef((props, ref) => <FilterList {...props} ref={ref} />),
FirstPage: forwardRef((props, ref) => <FirstPage {...props} ref={ref} />),
LastPage: forwardRef((props, ref) => <LastPage {...props} ref={ref} />),
NextPage: forwardRef((props, ref) => <ChevronRight {...props} ref={ref} />),
PreviousPage: forwardRef((props, ref) => (
<ChevronLeft {...props} ref={ref} />
)),
ResetSearch: forwardRef((props, ref) => <Clear {...props} ref={ref} />),
Search: forwardRef((props, ref) => <Search {...props} ref={ref} />),
SortArrow: forwardRef((props, ref) => <ArrowUpward {...props} ref={ref} />),
ThirdStateCheck: forwardRef((props, ref) => <Remove {...props} ref={ref} />),
ViewColumn: forwardRef((props, ref) => <ViewColumn {...props} ref={ref} />),
};
export default function TimeTrackingTable() {
return (
<>
<MaterialTable
title="$11.50 Menu"
icons={tableIcons}
columns={[{ title: "Section", field: "name" }]}
data={menuSections}
options={{
selection: true,
detailPanelColumnAlignment: "right",
sorting: false,
draggable: false,
paging: true,
pageSize: 5, // make initial page size
emptyRowsWhenPaging: false, // To avoid of having empty rows
tableLayout: "fixed",
}}
onSelectionChange={(rows, e) => {
console.log("rows", rows);
console.log("e", e);
}}
detailPanel={({ rowData }) => {
return <RenderDetails rowData={rowData} />;
}}
/>
<SelectOutsideOfTable />{" "}
</>
);
}
function RenderDetails({ rowData }) {
const [detailDataRow, setDetailDataRow] = useState({ ...rowData });
return (
<MaterialTable
icons={tableIcons}
title=""
columns={[
{
title: "Item",
field: "name",
headerStyle: { backgroundColor: "royalblue", color: "white" },
},
{
title: "Active",
field: "active",
headerStyle: { backgroundColor: "royalblue", color: "white" },
render: ({ active }) => <Switch checked={active} />,
},
]}
data={detailDataRow.PartnerMenuItems}
style={{
backgroundColor: "aliceblue",
}}
options={{
selection: true,
}}
onSelectionChange={(rows) =>
alert("You selected " + rows.length + " rows")
}
/>
);
}
const menuSections = [
{
name: "Salads",
PartnerMenuItems: [
{
name: "Farmers Salad",
active: true,
},
{
name: "Goat Cheese",
active: true,
},
{
name: "Champagne Vinaigrette",
active: true,
},
{
name: "Romaine Salad",
active: true,
},
{
name: "Cilantro Parmesan Dressing",
active: true,
},
{
name: "Asian Inspired Salad",
active: true,
},
{
name: "Cilantro Ginger Vinaigrette",
active: true,
},
{
name: "Beet Citrus Salad",
active: true,
},
{
name: "Maple Thyme Vinaigrette",
active: true,
},
],
},
.. etc i wont include all data here so not make the post too long
];
function SelectOutsideOfTable() {
const [data, setData] = useState([
{
fruit: "Apple",
id: 0,
},
{
fruit: "Orange",
id: 1,
},
]);
const toggleRowChecked = (row) => {
return row.tableData && row.tableData.checked
? !row.tableData.checked
: true;
};
const toggleSelectAll = () => {
const newData = data.map((row) => ({
...row,
tableData: {
checked: toggleRowChecked(row),
},
}));
setData(newData);
};
const columns = [
{
title: "Fruit",
field: "fruit",
},
{
title: "ID",
field: "id",
},
];
return (
<div>
<button onClick={toggleSelectAll}>Toggle Selection</button>
<MaterialTable
title="Select All External"
columns={columns}
data={data}
options={{
selection: true,
}}
/>
</div>
);
}
Package.json dependencies :
"devDependencies": {
"@babel/core": "^7.15.8",
"@babel/preset-env": "^7.15.8",
"@babel/preset-react": "^7.9.4",
"babel-loader": "^8.2.2",
"clean-webpack-plugin": "^4.0.0",
"css-loader": "^6.4.0",
"css-minimizer-webpack-plugin": "^3.1.1",
"html-webpack-plugin": "^5.4.0",
"html-webpack-skip-assets-plugin": "^1.0.3",
"jquery-migrate": "^3.3.2",
"mini-css-extract-plugin": "^2.4.3",
"react-json-view": "^1.21.3",
"style-loader": "^3.3.1",
"webpack": "^5.59.1",
"webpack-bundle-analyzer": "^4.5.0",
"webpack-cli": "^4.9.1",
"webpack-merge": "^5.8.0"
},
"dependencies": {
"@emotion/react": "^11.7.1",
"@emotion/styled": "^11.6.0",
"@material-table/core": "https://github.com/HRpuls/core.git#dist",
"@material-ui/core": "^4.12.3",
"@material-ui/data-grid": "^4.0.0-alpha.37",
"@material-ui/styles": "^4.11.4",
"@mui/icons-material": "^5.1.0",
"@mui/lab": "^5.0.0-alpha.56",
"@mui/material": "^5.2.8",
"@mui/styled-engine-sc": "^5.1.0",
"@mui/styles": "^5.2.3",
"@mui/x-data-grid": "^5.2.2",
"axios": "^0.24.0",
"bootstrap-table": "^1.19.1",
"chart.js": "^3.6.2",
"chartjs-plugin-datalabels": "^2.0.0",
"date-fns": "^2.27.0",
"jquery": "^3.6.0",
"jquery-ui": "^1.13.0",
"jspdf": "^2.5.0",
"jspdf-autotable": "^3.5.23",
"moment": "^2.29.1",
"moment-range": "^4.0.2",
"react": "^17.0.2",
"react-bootstrap": "^2.0.2",
"react-chartjs-2": "^4.0.0",
"react-csv": "^2.2.1",
"react-dom": "^17.0.2",
"react-highlight-words": "^0.17.0",
"react-hook-form": "^7.21.0",
"react-player": "^2.9.0",
"react-redux": "^7.2.6",
"react-router-dom": "^6.1.1",
"react-spinners": "^0.11.0",
"react-swipeable-views": "^0.14.0",
"react-table": "^7.7.0",
"react-video-js-player": "^1.1.1",
"redux": "^4.1.2",
"redux-logger": "^3.0.6",
"redux-promise-middleware": "^6.1.2",
"redux-thunk": "^2.4.1",
"signature_pad": "^4.0.1",
"styled-components": "^5.3.3",
"use-debounce": "^7.0.1"
}
The problem was caused by css. Found some legacy code that gave all checkboxes inputs the following :
[type="checkbox"]:not(:checked),
[type="checkbox"]:checked {
left: -99999px !important;
}
input[type="checkbox"],
input[type="radio"] {
width: auto;
}
So I just needed to set those values to their initial state and that did the trick.