I have a need to display a custom calculation in a Kendo UI Grid footer template. The built-in aggregates won't work for the business requirements. I have found a way to display results from a function in the footer template using code snippets shown below. The key points in this code are:
function calc() {
// assume this to be dynamically determined
var field = "Value";
// assume this to be dynamically determined
var dataSource = window.ds;
// some custom calc logic
var newValue = 0;
$.each(dataSource.data(), function(index, model) {
newValue += model.get(field);
});
return newValue;
}
$(document).ready(function() {
window.ds = new kendo.data.DataSource({
data: [
{Name:"One", Value:1},
{Name:"Two", Value:1},
{Name:"Three", Value:1},
{Name:"Four", Value:1},
{Name:"Five", Value:1}
],
pageSize: 10,
schema: {
id: "Name",
fields: {
Name: { type: "string"},
Value: { type: "number"}
}
}
});
$("#grid").kendoGrid({
dataSource: window.ds,
scrollable: false,
pageable: true,
editable: true,
columns: [
{ field: "Name", title: "Name" },
{ field: "Value", title: "Value",
footerTemplate: "Total: #=window.calc()#" }
]
});
});
The problem that I'm fighting is that the calculated value needs to be updated on-the-fly when the user changes one of the values in the column. This doesn't seem to be a straighforward way to make this happen in the Kendo UI Grid API.
What I've done so far is add a save handler to the Grid which makes a call to the Grid's refresh method.
$("#grid").kendoGrid({
dataSource: window.ds,
scrollable: false,
pageable: true,
editable: true,
columns: [
{ field: "Name", title: "Name" },
{ field: "Value", title: "Value",
footerTemplate: "Total: #=window.calc()#" }
],
save: function (e) {
e.sender.refresh();
}
});
This works (the footer values are updated immediately after the user change a value in the column), but it has a drawback. When changing a value and then clicking on another cell in the column, the newly clicked cell doesn't immediately go into edit mode (this functionality is apparently being short circuited by the call to the refresh method). The user then has to click the cell a second time to have it enter edit mode (yuck!).
There is a working example of this code at http://trykendoui.telerik.com/oVEV/4.
The solution that I have so far is less than ideal. Anyone know of a more elegant solution to this problem?
Try this... replace your footer template with this:
footerTemplate: "Total:<span id='myId'> #=window.calc()#</span>"
Notice how I put a span element with an ID in it? This makes it easy to change and update the total whenever needed. I gave it an id of myId
Now I think you want that total to update after every cell edit (and not necessarily when you save the grid). Every time the cell is successfully editted, the change
event is fired on the kendo dataSource. So fire up the recalculation in the change event. Your datasource will now look something like this:
window.ds = new kendo.data.DataSource({
data: [
//omitted code...
],
pageSize: 10,
schema: {
//omitted code...
},
change: function(e){
var total = window.calc();
$("#myId").html(total.toString());
}
});
No need to call that ugly refresh on the grid ;) . Here is your revised sample.
Nice solutions were provided i tried them all. But i think with set you can have everything. If you set the object item of the grid the footer template will be called. This will update the data in the Grid and the HTML and in Excel.
let grid = $('#grid').getKendoGrid(); // Kendo Grid
let dataItem = grid.dataItem(tr); // tr: JQuery (selected Row) get Item
let index= grid.items().index(grid.select()); // Selected Row get Row Index in DataSource of the Grid
let rowItem = grid.dataSource.at(index);
dataItem = data.length > 0 && data.length === 1 ? data : dataItem; // data is the new item with the same properties as the item datasource of the Grid.
dataItem.dirty = true;
// You can update all properties with the below code or just one it depends what you want to do. Aggregate functions will be called and Groupfooter and footer also.
for (let [key, value] of Object.entries(dataItem )) {
rowItem.set(key, value); //
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With