Telerik Kendo Dynamic Dropdown & Grid with Pre-selection

Kendo UI elements are incredibly powerful as they can use AJAX calls to dynamically pull and filter data with little to no effort as it all happens behind the scenes if it is set up properly. Here is a great reference for creating a dynamic or remotely bound drop-down (i.e the contents are fetched from the database) and here is a great reference for filtering another element based on the drop-down list selection. Now, I will show how we hooked the drop-down list to a grid, and then I'll show how we implemented pre-selection to properly filter the grid on the initial page visit. 

Filtering the grid from the drop-down:
First, set up the grid the grid with a toolbar. Here is a great example for this. Below, I've included a stripped down sample that includes the minimum functionality. 
@(Html.Kendo().Grid<Product>()
 .DataSource(dataSource => dataSource
  .Ajax()
  .Model(model => model.Id(m => m.Id))
  .ServerOperation(true)
  .Read(read => read.Action("Products_Read"))
 )
 .Columns(columns =>
 {
  columns.Bound(m => m.Name);
  columns.Bound(m => m.Cost);
  columns.Bound(m =. m.URL);
 })
 .ToolBar(toolbar =>
 {
 toolbar.Template(
  @<text>
   @(Html.Kendo().DropDownList()
    .Name("Categories")
    .DataValueField("Id")
    .DataTextField("Text")
    .Events(e => e
     .Change("filterChange")
    .DataSource(ds =>
    {
     ds.Read("Filter_Read");
    })
   )
   </text>);
 })
)

<script>
 function filterChange() {
  var value = this.value(),
   grid = $("#ProductGrid").data("kendoGrid");

  if (value) {
   grid.dataSource.filter({field:"Category",operator:"eq",value:parseInt(value)});
  }
 }
</script>
With the above setup, your grid should now filter based on the drop-down when a user selects a new item. But you may notice that although the  drop-down defaults to the first item, the grid does not filter based on that item at first! Now we must set up the grid so that it will initially filter.
Adding Pre-Selection to the Grid:
To begin, I am going to set the default value of the drop-down instead of letting it select the first item in the list. This can be achieved with a very simple line of code: 
    .DataSource(ds =>
    {
     ds.Read("Filter_Read");
    })
    .Value(ViewModel.InitialValue)
   )
   </text>);
Now, the drop-down will display our initial value upon page load, but it still does not initially filter. The reason is that the grid filter Javascript function from above is only being called when the user changes the selection with a click, but not when the value is initially set. The solution is to simply take advantage of the Kendo DataBound function and tie the same filtering function to it. Essentially, this is equivalent to telling the grid to filter both when a user changes the selection and when the drop-down is first loaded. Below is the complete drop-down toolbar code.
 toolbar.Template(
  @<text>
   @(Html.Kendo().DropDownList()
    .Name("Categories")
    .DataValueField("Id")
    .DataTextField("Text")
    .Events(e => e
     .Change("filterChange")
     .DataBound("filterChange"))
    .DataSource(ds =>
    {
     ds.Read("Filter_Read");
    })
    .Value(ViewModel.InitialValue)
   )
   </text>);
 })
(Note: NEVER use a $(document).ready function to try to access the value of the drop-down, it is AJAX'd in so you will usually get an empty value from the element. ALWAYS use DataBound.)

Now, the grid filters as expected! However, there is still one performance issue that goes unnoticed, and that is related to the default grid behavior. A remotely bound grid like ours will attempt to fill itself with data initially, which usually is fine. But, we are applying a filter to it as soon as the drop-down is populated, so there will be 2 grid read calls on page load! This can be compounded with the fact that the default grid read will be unfiltered, which may cause a significant performance hit if the data set is large. To force the grid to always cascade from the drop-down, we must turn off AutoBind which causes the grid to initialize without prompting. The complete grid code below forces complete dependence on the drop-down, exactly how we want it.
@(Html.Kendo().Grid<Product>()
 .AutoBind(false)
 .DataSource(dataSource => dataSource
  .Ajax()
  .Model(model => model.Id(m => m.Id))
  .ServerOperation(true)
  .Read(read => read.Action("Products_Read"))
 )
 .Columns(columns =>
 {
  columns.Bound(m => m.Name);
  columns.Bound(m => m.Cost);
  columns.Bound(m =. m.URL);
 })
Thanks for reading!

Published 9/9/16

Comments

Popular posts from this blog

ASP.NET Identity Remember Me

IIS Express Client Certificates

ASP.NET MVC - How to enable/disable CaC/Client Certificate authentication per area or route.