Skip to main content

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 wx-svelte-core library to render the column value. Use $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:

CheckboxCell
<script>
import { Checkbox } from "wx-svelte-core";

let { row, column, api } = $props();

function onChange(ev) {
const { value } = ev;

//execute update action
api.exec("update-cell", {
id: row.id,
column: column.id,
value,
});
}
</script>

<Checkbox value={row[col.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:

<script>
import { Grid } from "wx-svelte-grid";
import { getData } from "../data";
import { CheckboxCell } from "../custom/CheckboxCell.svelte";

const data = getData();

const columns = [
{
id: "checked",
cell: CheckboxCell,
header: "", // master checkbox will be rendered here in the next step
width: 36,
}
];
</script>
<Grid {data} {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. We use $props to access Grid api and the onaction property 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):

HeaderCheckboxCell
<script>
import { Checkbox } from "wx-svelte-core";

let { api, onaction } = $props();
let value = $state(false);

api.getReactiveState().data.subscribe(data => onCellCheck(data));

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 },
});

value = 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" },
});
}
</script>

<Checkbox bind: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 action function is invoked with the argument "header-checkbox", which then triggers the checkHeader function. In the checkHeader function, the state of all checkboxes in the column is updated based on the value of the header checkbox.

<script>
import { Grid } from "wx-svelte-grid";
import { getData } from "../data";
import CheckboxCell from "../custom/CheckboxCell.svelte";
import HeaderCheckboxCell from "../custom/HeaderCheckboxCell.svelte";

let { data } = $state(getData());
let api = $state();

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") {
data = api.getState().data.map(d => {
d.checked = value;
return d;
});
}
}
</script>

<Grid
{data}
{columns}
oncustomheadercheck={ev => onHeaderCheck(ev)} // Handle clicks on master checkbox
/>

Related articles: Adding custom content to cells