Cascade filter using ajax binding

5 posts, 1 answers
  1. Alexandra
    Alexandra avatar
    18 posts
    Member since:
    Sep 2015

    Posted 13 Jun Link to this post

    Hi,

    I have a grid with 2 fields that are connected so a cascade filter needs to be done on them. I manage to do this using Server binding because the UI was refreshed when a filter was done. But now I have to use Ajax binding but the cascade code does not work anymore because the UI is no longer called again

    @(Html.Kendo().Grid<TelerikTestModel>()
                .Name("grid2")
                .Columns(columns =>
                {
                    columns.Bound(product => product.MainField).UI("mainFilter"));
                    columns.Bound(product => product.DependentField).UI("subFilter"));
                })
                //                                   .Server()
                .DataSource(dataSource => dataSource.Ajax().PageSize(10).Read(read => read.Action("Data_Read", "Home")))
                .HtmlAttributes(new { style = "height: 550px;", @class = "myClass" })
                .Pageable(x => x.ButtonCount(5))
                .Sortable()
                .Filterable()
                .Scrollable()
                //.ColumnMenu()
                .Resizable(resize => resize.Columns(true))
                .Reorderable(reorder => reorder.Columns(true))
                .Events(e => e.FilterMenuInit("filterMenuInit"))
    )


    function mainFilter(element) {
            element.kendoDropDownList({
                dataSource: {
                    transport: {
                        read: "@Url.Action("FilterMenuCustomization_MainFilter")"
                    }
                },
                optionLabel: "--Select Value--",
                name: "mainFilter",
            });
        }
     
        function subFilter(element) {
     
            var dataSource = $("#grid").data("kendoGrid").dataSource;
     
            var filter = dataSource.filter();
     
            var value = -1
            if (filter && filter.filters) {
                var result = $.grep(filter.filters, function (e) {
                    return e.field == "MainField";
                });
     
                if (result.length == 1) {
                    value = result[0].value;
                }
            }
     
            element.kendoDropDownList({
                dataSource: {
                    transport: {
                        read: {
                            url: "@Url.Action("FilterMenuCustomization_SubFilter")",
                            dataType: "json",
                            data: {
                                mainFilter: value,
                            }
                        }
                    }
                },
                optionLabel: "--Select Value--",
                name: "subFilter",
            });
        }

    Two questions:
    1. in subFilter is there a way to get to the grid datasource without using the grid id? I need to make this code be used by any grid that has a dependent list
    2. for the Ajax-binding I was thinking to use the onFiltering event but how can I get to the filter control (to do the subFilter code)? On a page with 2 grids and the same dependent cascade filters I could not find a connection between the grid and the filter controls.

  2. Tsvetina
    Admin
    Tsvetina avatar
    2102 posts

    Posted 15 Jun Link to this post

    Hello Alexandra,

    I think that the filterMenuOpen event will help you with both your questions. It fires each time the filter menu is opened, so you can use it to check if a new filter was applied to the Grid and filter the child DropDownList based on it. 
    Using this event, you will be able to access the Grid from the event arguments (e.sender), so you don't need to find it by hard-coded id. Additionally, you have a reference to the currently opened filter menu element, so you can find the child DropDownList inside it, using a jQuery selector.

    Since the fluent API is currently missing a definition for FilterMenuOpen event, you can manually add a client event handler once the Grid is created (in the DataBound event).
    .Events(events=>events.DataBound("dataBound"))
    function dataBound(e) {
        e.sender.unbind("filterMenuOpen", filterMenuOpen);
        e.sender.bind("filterMenuOpen", filterMenuOpen);
    }

    I am calling unbind before bind, because without it a new event handler would be added with each re-bind of the Grid, resulting in filterMenuOpen executing multiple times in a row. Once the missing event is added to the fluent API, you will not need this. I logged an issue for you to follow here.

    Regards,
    Tsvetina
    Progress Telerik
    Try our brand new, jQuery-free Angular 2 components built from ground-up which deliver the business app essential building blocks - a grid component, data visualization (charts) and form elements.
  3. Alexandra
    Alexandra avatar
    18 posts
    Member since:
    Sep 2015

    Posted 15 Jun in reply to Tsvetina Link to this post

    Hi Tsvetina,

    Thank you for the suggestion. Can you help me also to rebind the dropdown list.

    Here is the code
    function filterMenuOpen(e) {
        if (e.field == "DependentField") {
            var dataSource = e.sender.dataSource;
     
            var filter = dataSource.filter();
     
            var value = -1
            // determine value correctly
     
            // this line seems to work
            e.container.find(".k-filter-help-text").text("Show sub functions from menu:");
     
            // this line return undefined regardless of what filter I try
            //var dropdownlist = e.container.find("[data-role=dropdownlist]:eq(1)").data("kendoDropDownList");
            //var dropdownlist = e.container.find("[data-role=listbox]:eq(1)").data("kendoListBox");
            var dropdownlist = e.container.find("[data-role=subfilter]").data("kendoDropDownList");
            var dataSource = new kendo.data.DataSource({
                transport: {
                    read: {
                        url: "@Url.Action("FilterMenuCustomization_SubFilter")",
                        dataType: "json",
                        data: {
                            mainFilter: value,
                        },
                    },
                },
            });
            // this is line :219:13
            dropdownlist.setDataSource(dataSource)
        }
    }


    And on console I get this error:
    jQuery.Deferred exception: Unable to get property 'setDataSource' of undefined or null reference TypeError: Unable to get property 'setDataSource' of undefined or null reference
       at filterMenuOpen (http://localhost:62884/:219:13)
       at trigger (http://localhost:62884/Scripts/kendo/kendo.all.min.js:25:6789)
  4. Answer
    Tsvetina
    Admin
    Tsvetina avatar
    2102 posts

    Posted 15 Jun Link to this post

    Hi Alexandra,

    It seems like you are not able to access the DropDownList element and the widget reference is null. Try inspecting the output of the DropDownList to see the exact attributes and classes applied. I tested the custom filter menu demo and I could access the span wrapper of the DropDownList, based on its title attribute set to "Value" by the Grid:
    http://dojo.telerik.com/@tsveti/aVIPi

    filterMenuOpen: function(e){
      if(e.field=="City"){
        var ddl = $("span[title='Value'] input").data("kendoDropDownList");
        alert(ddl.value());
      }
    }


    Regards,
    Tsvetina
    Progress Telerik
    Try our brand new, jQuery-free Angular 2 components built from ground-up which deliver the business app essential building blocks - a grid component, data visualization (charts) and form elements.
  5. Alexandra
    Alexandra avatar
    18 posts
    Member since:
    Sep 2015

    Posted 28 Aug in reply to Tsvetina Link to this post

    Hi Tsvetina,

    Thank you for the help. We manage to get the cascade filter to work. We had to implement also the filter event in order to remove the cascade filter but for that we did not require much help.

Back to Top