malloryCode.com

Kendo UI Grid in Sitefinity MVC Control

I've recently been working quite a bit with the Kendo UI toolkit, in particular with the grid. I've found that sometimes, mostly when the grid is first loaded, the filter parameter is null. When this happens, the the model binding doesn't work, and the correct ActionResult method is never called. In my case this has been when the grid is in an MVC user control in a Sitefinity implementation. I don't think there is a general error with the grid, since I wasn't able to find much on this in searches.

I typically use Ajax binding for grids, so the page will load, then there's a request back to the server to get the data. Here's a typical grid definition.

@(Html.Kendo()
      .Grid<ExportViewModel>()
      .Name( "ExportGrid" )
      .HtmlAttributes( new { style = "width: 750px;margin:50px;" } )
      .DataSource( s => s.Ajax()
                          .Model( m => m.Id( l => l.Id ) )
                          .Events( e => { e.Error( "error_handler" ); e.RequestEnd( "request_end" ); } )
                          .Read( r => r.Action( "Read", "Export" ).Data("send_page") ).PageSize( 15 )
      )
      .Columns( c =>
      {
          c.Bound( x => x.ApplicationName ).Filterable(false).Title( "Application" );
          c.Template( @<text>@item.FirstPage.FirstName @item.FirstPage.LastName</text> )
           .ClientTemplate( "#=FirstPage.FirstName# #=FirstPage.LastName#" )
           .Title( "Name" ).Width( 150 );          
          c.Bound( x => x.FirstPage.Email ).Width( 150 ).Filterable( false );
          c.Bound( x => x.ExportDate ).Filterable(false).Width( 135 ).Format( "{0:MM/dd/yyyy}" );
          c.Bound( x => x.ApplicationDate ).Width( 135 ).Format( "{0:MM/dd/yyyy}" );
       } )
       .ToolBar( t =>
                    {
                        t.Template( @<text>
                            <div class="toolbar">
                                <span id="delete-button" class="k-button">Delete</span>                                
                                <span style="float:right;" id="export-app1-button" class="k-button">App 1</span>
                                <label style="float:right;display:inline-block;vertical-align: middle;padding-right: .5em;">Export:</label>
                            </div>                            
                        </text> );
                     })
      .Filterable()
      .Pageable( p => p.Info( true ) )
      .Scrollable( s => s.Height( 490 ) )
)

You'll notice that I call the Data() method chained off the Read() method in the DataSource definition. The Data() method simply calls your own javascript function before sending the Ajax request for the data. It's in there that I examine the filter object and modify it if need be:

function send_page(data) {
     //data contains current request object
     if (data.filter.filters == undefined) {
         data.filter = "";
     }
 }

And that's it. The ActionResult signature looks like this:

[HttpPost]
public ActionResult Read( [DataSourceRequest] DataSourceRequest request )
{

and the problem was that without a value for the filter, the model binding never fully hydrated the POST variables into a proper DataSourceRequest, so the above method was never called.