Search code examples
kendo-gridkendo-asp.net-mvckendo-template

Kendo Grid Fluent API DataBound event for a Child Grid to show No Items text?


It feels like i've lost a lot of time looking for this and still haven't found anything that works (well, that works properly). I have a set of nested grids for a user requirement, each one drills down into the next one etc and all that is working fine. It's handled using client templates which do an ajax call when they get expanded, and then displays the data.

The problem I have is that if there are no results for one of the expansions, Kendo just shows the child grid header and nothing else. When I connect to the DataBound event (on the grid, .Events(e => e.DataBound("myJavaScriptFunctionName")) the this is not the Kendo Grid, and if I pass the name of the child kendo grid (which is unique by using the key in #=#) it gives me 0 items in my data source.

I'm not sure if this is because it does an ajax post back, and then OnDataBound fires before it comes back?

I just need to show a "No Items Found" message to make the user experience better when there is no data (this really only happens at the lowest level)

Enough with words, here is some example code:

    <script id="SecondToLastTemplate" type="text/kendo-tmpl">                    
        @(Html.Kendo().Grid<CustomerViewModel>()
              .Name("SumGrid_#=ResultYear#_#=ResultQuarter#_#=ResultMonth#_#=ResultWeekStart#_#=ResultDate#_#=Region#")
              .Columns(column =>
              {
                  column.Bound(x => x.CustomerName).Width("23%");                  
                  column.Bound(x => x.CustomerSummaryItem1).Width("14%");
                  column.Bound(x => x.CustomerSummaryItem2).Width("14%");
                  column.Bound(x => x.CustomerSummaryItem3).Width("14%");
              })

              .DataSource(dataBinding => dataBinding
                  .Ajax()
                  .PageSize(500)
                  .Read(read => read.Action("GetCustomerSummaryItems", Constants.Controller_ReportController, new
                  {
                      ResultYear = "#=ResultYear#"
                      ,ResultQuarter = "#=ResultQuarter#"
                      ,ResultMonth = "#=ResultMonth#"
                      ,ResultWeekStart = "#=ResultWeekStart#"
                      ,ResultDate = "#=ResultDate#"
                      ,Region = "#=Region#"                     
                  }))
              )
              .Scrollable(scrolling => scrolling.Enabled(false))
              .Sortable()
              .Filterable(filtering => filtering.Enabled(true))
              .ClientDetailTemplateId("LastTemplate")
              .Pageable(paging => paging.Enabled(false))
              .ToClientTemplate()
              )
</script>

    <script id="LastTemplate" type="text/kendo-tmpl">                    
        @(Html.Kendo().Grid<CustomerDetailsViewModel>()
              .Name("SumGrid_#=ResultYear#_#=ResultQuarter#_#=ResultMonth#_#=ResultWeekStart#_#=ResultDate#_#=Region#_#=CustomerName#")
              .Columns(column =>
              {
                  column.Bound(x => x.CustomerDetails1).Width("23%");
                  column.Bound(x => x.CustomerDetails2).Width("20%");
                  column.Bound(x => x.CustomerDetails3).Width("35%");
                  column.Bound(x => x.CustomerDetails4).Width("14%");
              })

              .DataSource(dataBinding => dataBinding
                  .Ajax()
                  .PageSize(500)
                  .Read(read => read.Action("GetCustomerDetails", Constants.Controller_ReportController, new
                  {
                      ResultYear = "#=ResultYear#"
                      ,ResultQuarter = "#=ResultQuarter#"
                      ,ResultMonth = "#=ResultMonth#"
                      ,ResultWeekStart = "#=ResultWeekStart#"
                      ,ResultDate = "#=ResultDate#"
                      ,Region = "#=Region#"                      
                      ,CustomerName = "#=CustomerName#"                      
                  }))
              )
              .Events(e => e.DataBound("onDataBound"))                 
              .Scrollable(scrolling => scrolling.Enabled(false))
              .Sortable()
              .Filterable(filtering => filtering.Enabled(true))
              .Pageable(paging => paging.Enabled(false))
              .ToClientTemplate()
              )
</script>

OnDataBound i've tried a few things, including the answer from this thread (Display a message within the Kendo grid when it's empty) with no luck. That one specifically always tells me I have 0 items in my data source (originally it was undefined, then I passed the grid name and still no luck).

Does anyone have a nice way to just say "No Items to display" while using the Fluent API with nested grids? I feel like i'm missing something simple here.

Thank you!


Solution

  • I figured these out:

    Since I was using an ajax post back, the grid items weren't always available when the DataBound event was being called for some reason (it feels like they should be, since it's DataBound, but it wasn't)

    I wrapped my no-results query in a setTimeout of 500ms so as to catch it, anything less and I would go back to the original error. I also modified the .find(... call to remove k-grid-header since that class wasn't outputting on my grid, and the colgroup was directly under the k-grid on the table.

    function DisplayNoResultsFound(e) {
        var self = e;
        setTimeout(function (item) {
            var grid = self;
            var dataSource = grid.data('kendoGrid').dataSource;
            var colCount = grid.find('colgroup > col').length;
            var noResultsMessage = '@Resources.Global.NoResultsFound';
    
            // If there are no results place an indicator row
            if (dataSource._view.length == 0) {
                grid.find('tbody')
                    .append('<tr class="kendo-data-row"><td colspan="' + colCount + '" style="text-align:center"><b>' + noResultsMessage + '</b></td></tr>');
            }
        }, 500); //Need to delay for ajax postback
    }
    

    This code is called by passing the jQuery grid item from the Databound Event:

    .Events(e => e.DataBound(DisplayNoResultsFound($('\\#SumGrid_#=ResultYear#_#=ResultQuarter#_#=ResultMonth#_#=ResultWeekStart#_#=ResultDate#_#=Region#_#=CustomerName#'))")
    

    Hope this helps someone else in the future!