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/vue-core library to render the column value. Use defineProps 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:
<script setup>
import { Checkbox } from "@svar-ui/vue-core";
const props = defineProps({ row: {}, column: {}, api: {} });
function onChange(ev) {
const { value } = ev;
//execute update action
props.api.exec("update-cell", {
id: props.row.id,
column: props.column.id,
value,
});
}
</script>
<template>
<Checkbox :value="row[column.id]" :onchange="onChange" />
</template>
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 setup>
import { Grid } from "@svar-ui/vue-grid";
import { getData } from "../data";
import { CheckboxCell } from "../custom/CheckboxCell.vue";
const data = getData();
const columns = [
{
id: "checked",
cell: CheckboxCell,
header: "", // master checkbox will be rendered here in the next step
width: 36,
}
];
</script>
<template>
<Grid :data="data" :columns="columns" />
</template>
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 defineProps 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):
<script setup>
import { ref } from "vue";
import { Checkbox } from "@svar-ui/vue-core";
const props = defineProps({ api: {}, onaction: { type: Function } });
const value = ref(false);
props.api.getReactiveState().data.subscribe(data => onCellCheck(data));
function onCellCheck(data) {
if (!data) ({ data } = props.api.getState());
const checked = data.every(d => d.checked === true);
// all rows are checked / unchecked
if (value.value !== checked) {
props.onaction &&
props.onaction({
action: "custom-header-check",
data: { value: checked },
});
value.value = checked;
}
}
function onChange(ev) {
const { value: val } = ev;
// manual click on a checkbox
props.onaction &&
props.onaction({
action: "custom-header-check",
// add eventSource to differentiate it from subscription to data
data: { value: val, eventSource:"click" },
});
}
</script>
<template>
<Checkbox v-model:value="value" :onchange="onChange" />
</template>
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 setup>
import { ref } from "vue";
import { Grid } from "@svar-ui/vue-grid";
import { getData } from "../data";
import CheckboxCell from "../custom/CheckboxCell.vue";
import HeaderCheckboxCell from "../custom/HeaderCheckboxCell.vue";
const data = ref(getData());
const api = ref();
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.value = api.value.getState().data.map(d => {
d.checked = value;
return d;
});
}
}
</script>
<template>
<Grid
:data="data"
:columns="columns"
:oncustomheadercheck="ev => onHeaderCheck(ev)"
/>
</template>
Related sample: Embedding actions
Related articles: Adding custom content to cells