Friday 19 April 2013

Kendo Grid: Ajax Binding while parsing Server side properties. Is this possible?


In a nutshell yes. I am currently migrating a website and I was in need of presenting data inside a Kendo Grid depending on the state of a server variable. There are different ways to achieve results, however my case was a bit peculiar. Let me first explain the goal here: We aim to be able to use .ClientTemplate templates in our Grid that actually render html based on the state of Server variables.

You might ask, why not just use the server side .Template? Simply enough, because it does not work with Ajax requests in the dataset. Please correct me if I am wrong, but no matter how hard I have tried, it never worked. So I came up with a workaround.


A Kendo Datagrid usually is given an enumeration as a datasource. 

 @(Html.Kendo().Grid((List<Thread>)Model.Threads)  
However, if the items inside this enumeration are too many, there is automatic paging supported.
Normally, when navigating among different pages, a postback takes place. This is the default behaviour for Kendo Grid. This can be changed by defining a datasource for the grid and assigning an actionresult method that delivers the same content as the predefined datasource (List<Thread>), only this time specifically in Json format:

 .DataSource(dataSource => dataSource  
     .Ajax()  
     .Read(read => read.Action("Threads_Read", "Forums").Data("additionalData"))
     )  
The datasource given above demands an Ajax postback and the data should be retrieved via the "Threads_Read" action method of the "Forums" controller. additionalData is a javascript function that resides on the html page and can be used as an intermediate means to pass server-side data back to the controller via Ajax.

What? Server-side? Really? YES! How?

 <script>  
   function additionalData() {  
     return {  
       forumId: @Model.ForumId  
       };  
   }  
 </script>  

I hope I have your attention now. The action on the controller side has as follows:

 // Method for getting ajax data for the ShowForum Kendo Grid  
 public ActionResult Threads_Read([DataSourceRequest]DataSourceRequest request, string forumId)  
 {  
       var threads = Forums.GetThreadsForForum(forumId).ToList();  
       DataSourceResult result = threads.ToDataSourceResult(request);  
       return Json(result);  
 }  
You see that forumId is easily passed to the action method via our little javascript.

Finally, the source code for the Kendo Grid has the following structure:

 @(Html.Kendo().Grid((Thread>)Model.Threads)  
     .Name("ThreadGrid")  
     .Columns(columns =>  
     {  
       columns.Bound(p => p.IsSticky).Title("").Sortable(true).Template(x => null)  
         .ClientTemplate(("# if ( IsSticky == true ) { # <img title='Sticky' alt='Sticky Thread' src='/Content/pin_red_16p.gif' /> # } #" +  
         "# if ( IsLocked == true ) { # <img title='Locked' alt='Thread is locked' src='/Content/lock_16p.gif' /> # } #" +  
         "# if ( IsDeleted == true ) { # <img title='Deleted' alt='Thread is deleted' src='/Content/delete_16p.gif' /> # } #")).Width(20);  
       columns.Bound(p => p.Subject).Template(x => null).Title("Thread").ClientTemplate("<a href='" +  
     Url.Action("ShowThread", "Forums") +  
     "?postId=#= ThreadID #'" +  
   ">" + "#= Subject #" + "</a><br /> by " + "#= Author #").Width(130);  
       columns.Bound(p => p.ThreadDate).Template(x => null).Title("Thread").ClientTemplate("by #= MostRecentAuthor # <br />" +  
         "#= ThreadDateString #").Width(70);  
       columns.Bound(p => p.TotalReplies).Title("Replies").Width(30);  
       columns.Bound(p => p.TotalViews).Title("Views").Width(30);  
     })  
   .DataSource(dataSource => dataSource  
     .Ajax()  
     .Read(read => read.Action("Threads_Read", "Forums").Data("additionalData"))  
     ))  

Keep your senses. This is easier than it looks. You can see that when creating templates I use both .Template and .ClientTemplate. I am not sure if this is really needed, you can try to skip the .Template(x => null) part. The important note here is that by using the structure above and although using Ajax, the string inside .ClientTemplate is parsed and according to the state of the Server-Side variables (for example IsSticky), there is a little image rendered on the client side.
This technique is clean because it does not render hidden images or other stuff when not needed on the client side.
Just to make things clear if they are not already, IsLocked, IsSticky etc. are properties that belong to the Thread object and they are parsed for each Thread within the List<Thread> that is given as a datasource to the Grid.

Hope this helps. Send me your questions if you have any.

No comments:

Post a Comment