.NET and me Coding dreams since 1998!

14Jun/120

Hacking the KendoUI grid

Here’s the thing: I love KendoUI grid!

It allows a server side desktop guy like me getting really nice results.In case you don’t have a clue what I am talking about go and look at their demo page for what KendoUI can do.

The only problem I have with KendoUI is that is “client side” UI technology which is I am sure the way to go in 2012 and perfect for many folks but I personally prefer doing my things as much I can in C# and use jscript when I have to.

Source code of today’s blog post can be found here

What is the problem?

Imagine a use case where you have a page where you enter a salary document which has a heading with  a date and number and a list of employees getting paid in that month.

Something like this

    
     public class CartHeaderModel
    {
        public string Number { get; set; }
        public DateTime Date { get; set; }

        public IList Items { get; set; }
    }

    public class CartItemModel
    {
        public string FullName { get; set; }

        public decimal NetAmount { get; set; }
        public decimal GrossAmount { get; set; }
    }

Client side story

To enable entering of this data using MVC, one might create a page with two text boxes and a  grid for showing and entering the employee data. (Similar example to this is cart and cart items and other master details LOB scenarios).

Something like this

    
<body>
        
	@model KendoPractice.Models.CartHeaderModel
        
	@using (Html.BeginForm((string)ViewBag.FormAction, "Home"))
        
	{
            
		<fieldset id="employee-new">
<legend>Podaci obračuna</legend>

<div>
@Html.LabelFor(m => m.Number)
@Html.TextBoxFor(m => m.Number)
@Html.ValidationMessageFor(m => m.Number)
</div>
<div>
@Html.LabelFor(m => m.Date)
@Html.TextBoxFor(m => m.Date)
@Html.ValidationMessageFor(m => m.Date)
</div>
<div id="grid"></div>

<input type="hidden" id="items" name="items" />
<input type="submit" value="Snimi podatke" />

</fieldset>
}
</body>

Few things are going on here:

  • There’s a form having two text boxes for header information
  • A grid is represented with just a empty div element with id=”grid”
  • There is one hidden input field with name “items” which would be used to post client grid state to server.

This is not supposed to be a post about Kendo (I am planning to do a few How-To later but not now) so here’s a very short explanation on how grid gets hooked up – it is quite simple.

            $("#grid").kendoGrid({
                dataSource: salaryDataSource,
                editable: { mode: "incell" },
                columns: [
                    { title: "Employee name", field: "FullName", width: 90, validation: { required: true } },
                    { title: "Net wage", field: "NetAmount", width: 90, validation: { required: true } },
                    { title: "Gross wage", field: "GrossAmount", width: 90, validation: { required: true } },
                ],
            });

As you can see, jquery selector gets a pointer on div with id grid and then wraps it with a .kendoGrid() having a few properties set up so the column headers etc. would be set. The data comes from a object called salaryDataSource which looks like this

	 
	var itemsData = @Html.Raw(ViewData["gridInitContext"]);
	var salaryDataSource = new kendo.data.DataSource({
                data: itemsData,

                change: function (e) {
                    var datas = salaryDataSource.data();
                    var result = "[";
                    var separator = "";
                    for (var i = 0; i < datas.length; i++) {
                        result += separator + JSON.stringify(datas[i]);
                        separator = ",";
                    }
                    result += "]";
                    $("#items").val(result);
                }
            });

 

Few interesting things here:

  • DataSource is hooked to a variable called itemsData which content is injected from server using the ViewData[“gridInitContext”]
  • Every time data source is changed, all of the bounded items are concatenated to a JSON array and value of a hidden field with an id items is set to that JSOn value.

To summarize the client side story:

  • KendoUI wraps the div and provides a rich grid UI functionality without any ajax calls
  • Initial data context of the grid is injected in a form of JSON collection from server using a ViewData[“gridInitContext”]
  • Every time bounded data of data source change the value of the hidden input field is getting updated to its JSON representation and on page post that value gets posted.

Server side story

Having in mind just summarized things, we are going to quickly check the Home controller now

    
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            //  in real world this comes from a repository etc - blog post only code
            var model = new CartHeaderModel()
            {
                Number = "12345",
                Date = DateTime.Now,
                Items = new List()
                {
                    new CartItemModel { FullName = "John Doe", GrossAmount = 123, NetAmount = 456},
                    new CartItemModel { FullName = "Jane Doe", GrossAmount = 555, NetAmount = 666},
                }
            };

            // pass to view JSON reprensentation of init context of the grid
            ViewData["gridInitContext"] = JsonConvert.SerializeObject(model.Items);

            return View(model);
        }

        [HttpPost]
        public ActionResult Index(string items, CartHeaderModel cartHeaderModel)
        {
            cartHeaderModel.Items = Newtonsoft.Json.JsonConvert.DeserializeObject>(items);

            // now with complete model we proceed as there was no kendo at all.
            return View();
        }
    }

Few interesting moments:

  • Index get action serialize to json items collection and store to view data so KendoUI can initialize grid  from it.
  • Post action gets two params where the items one contains JSON reprensentation of the client state which gets deserialized and the model is being completed.

image

What is the point of all this?

It is quite simple:

  • Have a server side code as ignorant as possible about the KendoUI.
  • Enable KendoUI to work in its full coolness.

In other words, I wanted KendoUI to be a toppling on my MVC cake, and not the part of the cake itself.

Samples on kendoui.com site are always showing the use case when you define CRUD controller just to feed the grid which IMHO breaks the MVC because half of your model gets to the server item by item using ajax calls, and half of it gets after page post.

I don’t know if this would be useful to anyone, but I wanted to share it with the community just in case there is someone out there.

Filed under: MVC Leave a comment
Comments (0) Trackbacks (0)

No comments yet.


Leave a comment

No trackbacks yet.