Creating a master checkbox in a header cell
The article instructs how to create a master checkbox for a column with checkboxes with the following behaviour:
- when all cells in a column are checked, a master checkbox in a header becomes checked as well
- checking/unchecking a master checkbox checks/unchecks all cells in a column
More about custom cell content you can find here.
Adding a checkbox to a table cell
We assume that we have data items with the checked field, where the boolean value is stored. You can use either an HTML checkbox or import Checkbox from @svar-ui/react-core library to render the column value. Use component props to access row and column data as well as Grid api.
Then we update row data by calling the update-cell action when the checkbox value is changed:
import { Checkbox } from "@svar-ui/react-core";
export default function CheckboxCell({ row, column, api }) {
function onChange(ev) {
const { value } = ev;
// execute update action
api.exec("update-cell", {
id: row.id,
column: column.id,
value,
});
}
return <Checkbox value={row[column.id]} onChange={onChange} />;
}
And finally we apply a checkbox component to a Grid column by using the cell property of a column element in the columns array:
import { Grid } from "@svar-ui/react-grid";
import { getData } from "../data";
import CheckboxCell from "../custom/CheckboxCell.jsx";
const data = getData();
const columns = [
{
id: "checked",
cell: CheckboxCell,
header: "", // master checkbox will be rendered here in the next step
width: 36,
},
];
export default function App() {
return <Grid data={data} columns={columns} />;
}
Adding a checkbox to a header cell
Ready-made components are added to the header/footer cells in the same way as to column cells. The component receives Grid api and an onAction callback prop to send a custom callback event to Grid. The event is sent each time a master checkbox changes its state either from manual clicks or data changes (when all rows are checked or one of them gets unchecked):
import { useState, useEffect } from "react";
import { Checkbox } from "@svar-ui/react-core";
export default function HeaderCheckboxCell({ api, onAction }) {
const [value, setValue] = useState(false);
useEffect(() => {
const unsubscribe = api.getReactiveState().data.subscribe(data =>
onCellCheck(data)
);
return () => unsubscribe();
}, []);
function onCellCheck(data) {
if (!data) ({ data } = api.getState());
const checked = data.every(d => d.checked === true);
// all rows are checked / unchecked
if (value !== checked) {
onAction &&
onAction({
action: "custom-header-check",
data: { value: checked },
});
setValue(checked);
}
}
function onChange(ev) {
const { value } = ev;
// manual click on a checkbox
onAction &&
onAction({
action: "custom-header-check",
// add eventSource to differentiate it from subscription to data
data: { value, eventSource: "click" },
});
}
return <Checkbox value={value} onChange={onChange} />;
}
Now you can import this component to Grid and apply it to a header cell by adding its name as the value of the cell parameter of the header element in the columns array. To handle clicks on a master checkbox, you need to handle the custom event it sends.
When the header checkbox is clicked, the onAction callback is invoked with the argument "custom-header-check", which then triggers the onHeaderCheck function. In the onHeaderCheck function, the state of all checkboxes in the column is updated based on the value of the header checkbox.
import { useState, useRef } from "react";
import { Grid } from "@svar-ui/react-grid";
import { getData } from "../data";
import CheckboxCell from "../custom/CheckboxCell.jsx";
import HeaderCheckboxCell from "../custom/HeaderCheckboxCell.jsx";
export default function App() {
const [data, setData] = useState(getData());
const api = useRef(null);
const columns = [
{
id: "checked",
cell: CheckboxCell,
header: [{ cell: HeaderCheckboxCell }], // master checkbox
width: 36,
},
];
// update all `checked` fields when header checkbox is clicked
function onHeaderCheck(ev) {
const { value, eventSource } = ev;
// ensure that the event source is "click"
// meaning it's a manual change (not from subscription to data)
if (eventSource === "click") {
setData(
api.current.getState().data.map(d => {
d.checked = value;
return d;
})
);
}
}
return (
<Grid
data={data}
columns={columns}
ref={api}
onCustomHeaderCheck={ev => onHeaderCheck(ev)} // Handle clicks on master checkbox
/>
);
}
Related sample: Embedding actions
Related articles: Adding custom content to cells