In Tabulator, I have a group header that shows calculated data, the grouping itself doesn't depend on this calculated data, I need to update a cell which is not used by the grouping and refresh the group.
Consider this example, In the group header I'm showing the sum of hours by group, update the cell "hours", and the header will not update because the hours column is not being used by the grouping function, how can I refresh the header?
var myTable = null;
$(() => {
var tableDiv = document.querySelector("#tableDiv");
console.log(tableDiv);
var tableData = [
{ id: 1, name: "Oli Bob", age: "12", hours: 1 },
{ id: 2, name: "Mary May", age: "12", hours: 2 },
{ id: 3, name: "Christine Lobowski", age: "42", hours: 3 },
{ id: 4, name: "Brendon Philips", age: "125", hours: 5 },
{ id: 5, name: "Margret Marmajuke", age: "16", hours: 1 },
{ id: 6, name: "Oli Bob", age: "12", hours: 1 },
{ id: 7, name: "Mary May", age: "12", hours: 2 },
{ id: 8, name: "Christine Lobowski", age: "42", hours: 4 },
{ id: 9, name: "Brendon Philips", age: "125", hours: 5 },
{ id: 10, name: "Margret Marmajuke", age: "16", hours: 2 },
];
for (i = 11; i <= 200; i++) {
tableData.push(
{ id: i, name: window.crypto.randomUUID(), age: i, hours: i }
);
}
var columnConfig = [
{ title: "Name", field: "name", width: 150 },
{ title: "Age", field: "age", hozAlign: "left", editor: "input" },
{ title: "Hours", field: "hours", width: 150, editor: "number" },
];
myTable = new Tabulator(tableDiv, {
data: tableData,
columns: columnConfig,
//height: "200px",
groupBy: function (data) {
//data - the data object for the row being grouped
return data.age; //groups by age
},
groupHeader: function (value, count, data, group) {
//value - the value all members of this group share
//count - the number of rows in this group
//data - an array of all the row data objects in this group
//group - the group component for the group
return `Age: ${value} - Hours: ${data.map(i => i.hours).reduce((a, b) => a + b)}`;
},
groupUpdateOnCellEdit: true,
maxHeight: "100%"
});
myTable.on('cellEdited', (c) => {
//what can I do here?
});
})
div.example-table {
height: 400px;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- <link href="https://unpkg.com/tabulator-tables@5.6.1/dist/css/tabulator.min.css" rel="stylesheet">
<script type="text/javascript" src="https://unpkg.com/tabulator-tables@5.6.1/dist/js/tabulator.min.js"></script> -->
<link href="https://unpkg.com/tabulator-tables@6.2.1/dist/css/tabulator.min.css" rel="stylesheet">
<script type="text/javascript" src="https://unpkg.com/tabulator-tables@6.2.1/dist/js/tabulator.min.js"></script>
<script src="https://code.jquery.com/jquery-3.7.1.min.js"
integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=" crossorigin="anonymous"></script>
<script type="text/javascript" src="./index.js"></script>
<link href="./index.css" rel="stylesheet">
<title>Simple HTML Page</title>
<style>
</style>
</head>
<body>
<div id="tableDiv" class="example-table"></div>
</body>
</html>
I can use the cellEdited callback to update the group, but how?
myTable.on('cellEdited', (c) => {
//what can I do here?
});
Things I have tried:
Redraw the table
myTable.on('cellEdited', (c) => {
myTable.redraw(); //does nothing
});
Redraw full
myTable.on('cellEdited', (c) => {
myTable.redraw(true); //works but the vertical scroll jumps to the top
});
refreshActiveData
myTable.on('cellEdited', (c) => {
myTable.rowManager.refreshActiveData(); //works but the vertical scroll jumps to the top
});
If I remove the height of the table the scroll problem goes away, but I lose the frozen column headers
What can be done?
If you can live without using the VirtualDOM, you can track the scrollTop
position of the tabulator-holder
div to get back to the same scroll position after cell is edited. First, you would move the groupHeader
function out (gHeader
in my example below). In the cellEditing
event, you would get the initial scrollTop position and assign it to a variable, then in the cellEdited
event, you would re-set the group header using myTable.setGroupHeader(gHeader)
(myTable.redraw(true)
also works but will be slower) and then restore the scrollTop position.
I would be curious to see is there is a better way as well since this is a bit hacky but works. Here is the example:
var myTable = null;
$(() => {
var tableDiv = document.querySelector("#tableDiv");
var tableData = [
{ id: 1, name: "Oli Bob", age: "12", hours: 1 },
{ id: 2, name: "Mary May", age: "12", hours: 2 },
{ id: 3, name: "Christine Lobowski", age: "42", hours: 3 },
{ id: 4, name: "Brendon Philips", age: "125", hours: 5 },
{ id: 5, name: "Margret Marmajuke", age: "16", hours: 1 },
{ id: 6, name: "Oli Bob", age: "12", hours: 1 },
{ id: 7, name: "Mary May", age: "12", hours: 2 },
{ id: 8, name: "Christine Lobowski", age: "42", hours: 4 },
{ id: 9, name: "Brendon Philips", age: "125", hours: 5 },
{ id: 10, name: "Margret Marmajuke", age: "16", hours: 2 },
];
for (i = 11; i <= 200; i++) {
tableData.push(
{ id: i, name: window.crypto.randomUUID(), age: i, hours: i }
);
}
var columnConfig = [
{ title: "Name", field: "name", width: 150 },
{ title: "Age", field: "age", hozAlign: "left", editor: "input" },
{ title: "Hours", field: "hours", width: 150, editor: "number" },
];
const gHeader = (value, count, data, group) => {
return `Age: ${value} - Hours: ${data.map((i) => i.hours).reduce((a, b) => a + b)}`
}
myTable = new Tabulator(tableDiv, {
data: tableData,
columns: columnConfig,
height: '300px',
groupBy: function (data) {
//data - the data object for the row being grouped
return data.age //groups by age
},
groupHeader: gHeader,
groupUpdateOnCellEdit: true,
renderVertical: 'basic'
})
let top
myTable.on('cellEditing', (c) => {
top = document.querySelector('.tabulator-tableholder').scrollTop
})
myTable.on('cellEdited', (c) => {
myTable.setGroupHeader(gHeader)
document.querySelector('.tabulator-tableholder').scrollTop = top
})
})
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- <link href="https://unpkg.com/tabulator-tables@5.6.1/dist/css/tabulator.min.css" rel="stylesheet">
<script type="text/javascript" src="https://unpkg.com/tabulator-tables@5.6.1/dist/js/tabulator.min.js"></script> -->
<link href="https://unpkg.com/tabulator-tables@6.2.1/dist/css/tabulator.min.css" rel="stylesheet">
<script type="text/javascript" src="https://unpkg.com/tabulator-tables@6.2.1/dist/js/tabulator.min.js"></script>
<script src="https://code.jquery.com/jquery-3.7.1.min.js" integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=" crossorigin="anonymous"></script>
<script type="text/javascript" src="./index.js"></script>
<link href="./index.css" rel="stylesheet">
<title>Simple HTML Page</title>
<style>
</style>
</head>
<body>
<div id="tableDiv" class="example-table"></div>
</body>
</html>