Change the Background Color of Kendo UI Grid Row on Load

The Kendo UI Grid, from Telerik, looks and feels excellent right out of the box.  However, there are times where your UI could benefit from tweaking the standard look and feel to make something standout, to draw the users attention to an important piece of information or highlight some operational need.  Kendo makes this easy.

It’s no secret, that I am a huge fan of the Kendo package.  One of the many reasons why, is that it is built on open standards and functions as you would expect a web library should.  In this example we are going to highlight rows in the Kendo Grid based on the data in a specific column in each row. And we are going to use standard JQuery functions to do so.

Our demo grid is going to display a list of transactions to our user.  We want to make it super clear which transactions are DEPOSITS and which transactions are WITHDRAWALS.  The full source for the demo is here: https://bitbucket.org/abumgardner/kendo-ui-grid-row-color-demo/ 

And our end result should look like this:

Changing row background color based on data in the row

Changing row background color based on data in the row

To start we create a standard POCO to represent our transactions and place this in the Models folder.

public class Transaction
{
  public string Description { get; set; }
  public bool deposit { get; set; }
  public decimal Amount { get; set; }
}

Then we can define a basic Kendo Grid.  We are not doing anything fancy with the grid at this point.  It is just a simple Kendo Grid that is added to our index.cshtml view.

@(
    Html.Kendo().Grid<ColorGridDemo_Two.Models.Transaction>()
        .Name("DemoGrid")
        .Columns(columns =>
        {
            columns.Bound(p => p.Description).Title("Transaction Description");
            columns.Bound(p => p.deposit).Title("Deposit?");
            columns.Bound(p => p.Amount).Format("{0:c}");
        })
        .Sortable()
        .Filterable()
        .Events(evnts => evnts.DataBound("ColorMeBad"))
        .DataSource(datasource => datasource.Ajax().PageSize(10)
                  .Read(read => read.Action("Transactions_Read", "Home"))
                )
)

If you notice in our grid definition we have the following line:

.Events(evnts => evnts.DataBound("ColorMeBad"))

We are going to use the Grids built in DataBound event to fire off a piece of Javascript that will alter the css in use.  To learn more about the events see the Telerik website here: https://docs.telerik.com/kendo-ui/api/javascript/ui/grid  The docs tell us that the databound event is “Fired when the widget is bound to data from its data source.” That description is not super clear, but it fires after the datasource is bound.  If you ever need to take some action immediately before the datasource is bound, then look for the databinding event.  

When we setup our grid we told it to fire a javascript function named ColorMeBad on the DataBound event.  This is where we will do the actual work of coloring the rows.

function ColorMeBad() {
        var grid = $("#DemoGrid").data("kendoGrid");
        var data = grid.dataSource.data();
        $.each(data, function (i, row) {
            if (row.deposit) {
                $('tr[data-uid="' + row.uid + '"] ').css("background-color", "green");
            } else {
                $('tr[data-uid="' + row.uid + '"] ').css("background-color", "red");
            }
        })
    }

Here we use JQuery to get a reference to the grid, use the grids dataSource object to get the data, then iterate over the rows.  We are checking the deposit property on our transaction model, and if true using css to change the background color to green, otherwise red.

You can clone the demo project here: https://bitbucket.org/abumgardner/kendo-ui-grid-row-color-demo/ 

Kendo UI Grid – Persist Expanded Row

The Kendo UI Grid is one of the most versatile grids on the market today.  The flexibility and usefulness is unparalleled and thus it is a staple in my web development toolkit.  One of my more popular use cases involves providing a Grid of data, where you can select a row and “drill in” or “expand” into to see additional details.  Sometimes those details are another grid, sometimes it is simply another view.  Kendo makes this super easy and it is demo’ed on their site here: http://demos.telerik.com/kendo-ui/grid/detailtemplate

 

One of the most common use cases I come across using the grid consist of the following.  The user selects and item in the grid, expands the row to "Drill In" to the details.  The user then navigates away from the page and when they come back they expect the grid to be in the same state.  Unfortunately, without a little extra work this is not possible.  Out of the box, when you navigate back to the page the grid will have defaulted back to its default state with all rows collapsed.  Here is a demonstration of this in action:

Before

Here is the high-level plan of attack:

  1. Save a unique value from each record as it is expanded.
  2. Each time the grid loads, check for the value.
  3. If present, expand saved row.

To accomplish step one, we are going to need to hook into one of the many Kendo UI events.  In this case, we are going using the DetailExpand event to call some custom javascript that will grab the expanded row and post it back to our controller in order to stash it in the session.  The DetailExpand event is detailed here: http://docs.telerik.com/kendo-ui/api/javascript/ui/grid#events-detailExpand

1
.Events(events => events.DetailExpand("GridExpanded"))

Now our grid will call the GridExpanded() JavaScript function each time a row in the Grid is expanded.  This function will have two jobs.  First, grab a unique value identifying the row, then post that value to our controller.

1
2
3
function GridExpanded(e) {
$.post("@Url.Action("SetExpandedRow", "Home")", { rowident: e.sender.dataItem(e.masterRow).id });
}

There is a lot packed into this one line function.  We are using the JQuery POST function, in order to do an HTTP Post with the data back to the controller.  To get the URL we are posting to, we are using the very handy ASP.net MVC URL helper, @URL.action.  This method takes the name of the Action and Controller and returns the appropriate relative URL. We are then providing the POST a callback function to provide the data.  In this case we are posting a name value pair named rowident where the value is the id column of our grid row.  Notice we are using the sender information passed to us from the grid to get the dataItem, and then use the dataItem to get the id. In this example the id column is a unique value in each row.  This could be any column, so long as it is unique.

The JavaScript is only one side of the equation.  The script is posting the unique row value to our controller via the SetExpandedRow action.  We now need to define the action that will catch this value and stash in the session.

1
2
3
4
5
6
[HttpPost]
public ActionResult SetExpandedRow(string rowident)
{
Session["ExpandedRowId"] = rowident;
return new EmptyResult();
}

Here we are simply throwing the expanded value in the session.  You may need to persist this in some other manner depending on your requirements.

Now that we have the last expanded row value stashed in the session we need have the Grid check each time it loads it data.  If we have a selected row value, then we need to expand that row.  We will do this by using the DataBound event.

1
.Events(events => events.DetailExpand("GridExpanded").DataBound("ExpandStashedSite"))

Each time the Grid fires its DataBound event it will now execute our JavaScript function, ExpandStashedSite().

 1
2
3
4
5
6
7
8
9
10
11
12
function ExpandStashedSite(e) {
var grid = $("[id^='Grid_1']").data("kendoGrid");
var data = grid.dataSource.data();
var len = data.length;

for (var i = 0; i < len; i++) {
var row = data[i];
if (row.id == '@string.Format("{0}", Session["ExpandedRowId"] )') {
grid.expandRow("tr[data-uid='" + row.uid + "']"); // expands the row with the specific uid
}
}
}

This function uses JQuery selectors to get our Grid.  It then gets the data currently loaded to the grid and starts looping through the records.  It checks each records id column to see if it matches our stashed value which it is simply grabbing from the session.  If it matches, then it uses the grids expandRow function.

When you put it all together it looks like this:

After

Notice that when you navigate back to the grid page, it retains the expanded grid.  This example was a simple one where we only stash the last expanded row.  However, it would be trivial to modify this code to retain all expanded rows.

Here is what the view looks like when you have it all together.

 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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
@{
ViewBag.Title = "Home Page";
}

<div class="container">
<div class="row">
<h4 class="page-header">Databound Event Demo</h4>
</div>
<div class="row">
<div id="PercentError" class="alert alert-danger" style="display: none;"></div>

@(
Html.Kendo().Grid<KendoUIGridEventsBlog.Models.DemoModel>()
.Name("Grid_1")
.Columns(columns =>
{
columns.Bound(p => p.id).Hidden(true);
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(events => events.DetailExpand("GridExpanded").DataBound("ExpandStashedSite"))
.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"))
)
.ClientDetailTemplateId("DrillInTemplate")
)
</div>

<script id="DrillInTemplate" type="text/kendo-tmpl">
@(
Html.Kendo().Grid<KendoUIGridEventsBlog.Models.DemoModel>()
.Name("Grid_DrillIn")
.Columns(columns =>
{
columns.Bound(p => p.Column1).Title("Column 1");
columns.Bound(p => p.Column2).Title("Column 2");
})
.Sortable()
.Filterable()
.DataSource(datasource => datasource
.Ajax()
.Model(model =>
{
model.Id(p => p.Column1);
})
.Read(read => read.Action("Demo_Read", "Home"))
).ToClientTemplate()
)
</script>

</div>

<script type="text/javascript">

function GridExpanded(e) {
$.post("@Url.Action("SetExpandedRow", "Home")", { rowident: e.sender.dataItem(e.masterRow).id });
}

function ExpandStashedSite(e) {
var grid = $("[id^='Grid_1']").data("kendoGrid");
var data = grid.dataSource.data();
var len = data.length;

for (var i = 0; i < len; i++) {
var row = data[i];
if (row.id == '@string.Format("{0}", Session["ExpandedRowId"] )') {
grid.expandRow("tr[data-uid='" + row.uid + "']"); // expands the row with the specific uid
}
}
}
</script>

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!

Read more

Update: A Better Way to Make a Read Only column in Kendo UI Grid Edit Mode

Shortly after hitting publish on my last blog post, I received an email from Lohith (https://about.me/kashyapa), a Technical Evangelist with Telerik in India.  He had seen my post and pointed me to the documentation that allows for a much easier method of accomplishing this task.  This is yet another example of why Telerik is such an awesome company and I am more than happy to hand over my money for a superb set of development components.

Read more

Make a Read Only column in Kendo UI Grid Edit Mode

When it comes to JavaScript and HTML 5 web application components there is absolutely none better than Kendo UI (http://www.telerik.com/kendo-ui).  Kendo UI is not cheap and there can be a slight learning curve, but it is a spectacular piece of software.  If you work in ASP.net MVC then spend the money and buy the server extensions.  Amazing.

Read more