Kendo UI Grid - Sum a Column on Load

While working on a recent project I came across a need to sum a specific column of the Kendo UI Grid in my application after it loaded.   Specifically, I had a grid where one column of each row was the “Percent of Total”.  What the client requested, was that a message be displayed at the top of the screen whenever the sum of that column in all the rows of the grid did not equal 100%.

 

My first thought, was that I would handle this server side.  I could calculate the sum before I ever sent the data to the view.  Drop that sum in ViewData and I would be off to the races.

 

The problem with this approach is that in this project I was utilizing the excellent inline edit capabilities of the Kendo UI Grid.  This meant that the user could add a new row without the screen refreshing.  Without that server round trip, I could not be sure what I was showing the user was correct.  I needed something client side!

 

Here was my solution:

  1. Place a div at the top of the screen to hold the message, hidden.
  2. Create a JavaScript function to be called by the Kendo Grid DataBound event.
  3. If the calculation doesn’t sum to 100% then show the message.

First, place the message at the top of the screen but style it so that it is not shown.

1
<div id="PercentError" class="alert alert-danger" style="display: none;"></div>

Second, I took advantage of one of the many events available on the Kendo UI Grid.  Specifically, I used the dataBound event.  The documentation for the Kendo Grid has this to say about when this event is fired.

“Fired when the widget is bound to data from its data source.” 

This is not very helpful, in my opinion.  This event actually gets fired after the grid loads its data.  If you need to take action immediately before, then you should look at the dataBinding event instead. 

Using Events in Kendo grid is super easy. 

1
.Events(events => events.dataBound("DoesColumnEqualOneHundred"))

Adding this line to the Grid tells the grid to call the JavaScript function DoesColumnEqualOneHundred() after it loads data.  Here is how the full Grid code looks with the event.

 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
@(
Html.Kendo().Grid<KendoUIGridEventsBlog.Models.DemoModel>()
.Name("Grid_1")
.Columns(columns =>
{
columns.Bound(p => p.Column1).Title("Column 1");
columns.Bound(p => p.Column2).Title("Column 2");
columns.Bound(p => p.dPercentColumn).Title("Percent Column");
columns.Command(command => { command.Edit(); command.Destroy(); }).Width(210);
})
.ToolBar(tools =>
{
tools.Create();
tools.Excel();
})
.Sortable()
.Editable(editable => editable.Mode(GridEditMode.InLine))
.Filterable()
.Resizable(resize => resize.Columns(true))
.Events(gridevents => gridevents.DataBound("DoesColumnEqualOneHundred"))
.DataSource(datasource => datasource
.Ajax()
.Model(model =>
{
model.Id(p => p.Column1);
})
.Read(read => read.Action("Demo_Read", "Home"))
.Create(create => create.Action("Demo_Create", "Home"))
.Update(update => update.Action("Demo_Update", "Home"))
.Destroy(update => update.Action("Demo_Delete", "Home"))
)
)

Now we just need to write the JavaScript to calculate the value and display the message if needed:

 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<script type="text/javascript">
function DoesColumnEqualOneHundred(e) {
var total = 0;
var grid = $("[id ^= 'Grid_']").data("kendoGrid");
var gridData = grid.dataSource.view();
for (var i = 0; i < gridData.length; i++) {
total += gridData[i].dPercentColumn;
}

if (total == 100) {
$("#PercentError").hide();
} else {
$("#PercentError").text('Currently Percent of Project = ' + total + '%.');
$("#PercentError").show();
}
}
</script>

The interesting part of this simple JavaScript is how I am getting the data to sum.  We know that we want to sum the values for the dPercentColumn and Kendo makes it super simple for us to grab that value.

First, use a standard JQuery selector to grab the Grid.  When using the selector make sure you use the same name you used in .Name() when creating your grid.  In my example I used the ^= (Attribute Starts With) selector, even though it is not really needed here.  I often have lots of sub-grids and that is where the starts with comes in handy.

1
var grid = $("[id ^= 'Grid_']").data("kendoGrid");

Once you have your grid, we need to grab the datasource and loop through each record.

1
2
3
4
var gridData = grid.dataSource.view();
for (var i = 0; i < gridData.length; i++) {
total += gridData[i].dPercentColumn;
}

The rest of the function is simply to do the calculation and show/hide our message.

This technique works well on non-paginated grids, as the datasource object the grid returns you only has the actual data that is visible on the screen for performance reasons.  If you needed a paginated grid, you could hook into the same event and make an Ajax call to the server to get the total.