Server fIlter on chart datasource doesn't work

4 posts, 0 answers
  1. Milos
    Milos avatar
    2 posts
    Member since:
    Aug 2018

    Posted 07 Sep 2018 Link to this post

         Hi, here is the problem. I have mvc chart set in razor view. Here is the definition:

        <div class="demo-section k-content wide">
                    @(Html.Kendo().Chart<List<Novolyze.VOD.WebUI.Models.ChartSource>>()
                    .AutoBind(false)
                    .DataSource(dataSource => dataSource            
                    .Read(read => read
                        .Action("DailyStatisticJson", "Production")
                        //.Data("getFilterParams")
                    )
                    .Group(group => group
                        .Add<string>("SeriesName"))
                
                    )           
                    .Name("dailyStatisticChart")
                    .Title("Daily Statistic")
                    .Zoomable(zoomable => zoomable
                        .Mousewheel(mousewheel => mousewheel
                            .Lock(ChartAxisLock.Y))
                        .Selection(selection => selection
                            .Lock(ChartAxisLock.Y)))
                    .Pannable(pannable => pannable
                        .Lock(ChartAxisLock.Y))
                    .Legend(legend => legend
                        .Visible(false)
                    )
                    .SeriesDefaults(seriesDefaults => seriesDefaults
                        .Column()
                    .Stack(true)
                    )
                    .Series(series => series
                        .Column(model => model).Field("Value").CategoryField("Category").ColorField("ColorName")
                    )                    
                    .CategoryAxis(axis => axis
                        .Date()
                        .BaseUnit(ChartAxisBaseUnit.Days)
                        .Labels(labels => labels
                            .Rotation("auto"))
                    )                    
                )

    I also have contlroler method:

    public ActionResult DailyStatisticJson([DataSourceRequest] DataSourceRequest request)
    {    

      //Some logic and return datasource JSON, that works well

    }

    I want to refresh the chart with new data based on some external filtering. I have the following Javascript code that should do the trick, but it doesn't

     function executeFilter(filters) {  
            var chart = $("#dailyStatisticChart").data("kendoChart");
            if (chart) {
                chart.dataSource.filter(filters);
                //chart.dataSource.read();                   
            }
        }    

    The point is: if I call just filter() and not the read(), chart data disappear, controller is not called. If I uncomment read(), then controller is called, but filter property is empty in the controller parameter. I can find the workaround to pass additional data with uncommenting Data to datasource definition but then I will use another param in controller, not DatasourceRequest, which will be uglier. Is there a solution with filter?

  2. Tsvetina
    Admin
    Tsvetina avatar
    2481 posts

    Posted 11 Sep 2018 Link to this post

    Hi Milos,

    There might be a problem with the format of the request when filtering criteria is added. Could you try declaring your DataSource like this:
    .DataSource(ds => ds
        .Custom()
        .Schema(schema=>schema.Data("Data"))
        .Transport(transport=> {
            transport.Read(r => r.Action("DailyStatisticJson", "Production"));
        })
    )

    and the controller method signature and structure like this:
    public ActionResult DailyStatisticJson([DataSourceRequest]DataSourceRequest request)
    {
        // obtain a reference to the unfiltered data set or context
        var result = ...
        // call ToDataSourceResult() to apply the filtering
        return Json(result.ToDataSourceResult(request));
    }

    If this change doesn't help, check the browser developer tools (F12 key) Network tab for any failed requests to the server and if there are any, check their response for server error messages.

    Regards,
    Tsvetina
    Progress Telerik
    Get quickly onboarded and successful with your Telerik and/or Kendo UI products with the Virtual Classroom free technical training, available to all active customers. Learn More.
  3. Milos
    Milos avatar
    2 posts
    Member since:
    Aug 2018

    Posted 12 Sep 2018 in reply to Tsvetina Link to this post

    There is no change in your solution comparing to mine, except if you think on blank space in method argument. That is not a problem. There is also no error, nor failed request, just filter is empty. OK, I will try to help with as much details as I found. 

    Point is that when filter method from chart datasource is called it does not create filter field in post body like grid datasource filter method. Grid filter method formats it in some way with some ~ characters, and chart filter simply put filter arguments as an array in post body. Because of that reason, when filter called from a grid, i get filter property in DataSourceRequest argument in controller filled as it should be and in the case of chart filter called filter property in the controller argument is empty. 
    Conclusion is that model binder [DataSourceRequest] doesn't know how to interpret array from post body and put it into an object.

    So, the problem is why chart.datasource.filter doesn't format filter like grid.datasource.filter
    I saw that datasources for grid and chart are different objects. Argument in datasource method for grid is DataSourceBuilder and for chart is ReadOnlyAjaxDatasourceBuilder.
    Obviously the first one knows how to create filter, the second one doesn't know which means that chart can't have filter feature.

    Please just confirm to me if this is correct or I can use filter for chart on some other way. 
  4. Tsvetina
    Admin
    Tsvetina avatar
    2481 posts

    Posted 13 Sep 2018 Link to this post

    Hello Milos,

    My suggestion included also a Custom DataSource, so that its schema can be configured to parse the DataSourceResult returned by the server. You would still needed it, but after your description, I think I know what else is missing.

    When using the Chart with a regular DataSource, it makes a GET request by default, while the Grid DataSource makes a POST request when default configuration is used. So, the custom DataSource also needs to use the POST verb:
    .DataSource(ds => ds
        .Custom()
        .Schema(schema => schema.Data("Data"))
        .Transport(transport =>
        {
            transport.Read(r => r.Action("DailyStatisticJson", "Production").Type(HttpVerbs.Post));
        })
    )

    To demonstrate that a Chart should work with such a configuration, I am attaching a sample project, where a Chart is filtered externally on button click (bin folder is removed, so the references need to be restored before running the sample).

    Following is the relevant code from the sample if you only want to view it:
    <button onclick="filter()">Show values > 100</button>
    @(Html.Kendo().Chart<TelerikMvcApp12.Models.ProductViewModel>()
        .Name("chart")
        .Series(series => series
            .Column(model => model).Field("UnitsInStock").CategoryField("ProductName")
        )     
        .DataSource(ds => ds
            .Custom()
            .Schema(schema => schema.Data("Data"))
            .Transport(transport =>
            {
                transport.Read(r => r.Action("Products_Read", "Grid").Type(HttpVerbs.Post));
            })
        )
    )
    <script>
        function filter() {
            var chart = $("#chart").data("kendoChart");
            chart.dataSource.filter({field: "UnitsInStock", operator: "gt", value: 100});
        }
    </script>

    public ActionResult Products_Read([DataSourceRequest]DataSourceRequest request)
    {
        var result = Enumerable.Range(1, 20).Select(i => new ProductViewModel
        {
            ProductID = i,
            UnitsInStock = i * 10,
            ProductName = "Product " + i,
            Discontinued = i % 3 == 0
        });
     
        return Json(result.ToDataSourceResult(request));
    }


    Regards,
    Tsvetina
    Progress Telerik
    Get quickly onboarded and successful with your Telerik and/or Kendo UI products with the Virtual Classroom free technical training, available to all active customers. Learn More.
Back to Top