This is a migrated thread and some comments may be shown as answers.

filter with single selection dropdown instead of multi-check

6 Answers 665 Views
Grid
This is a migrated thread and some comments may be shown as answers.
Daniel
Top achievements
Rank 1
Daniel asked on 23 Jul 2018, 06:59 AM

Hello

As a reference I use the sample in https://demos.telerik.com/aspnet-mvc/grid/filter-multi-checkboxes. By clicking on the filter icon, a multi-check drop-down is displayed. I'd like to show a single selection drop-down (containing the distinct row values in the corresponding column as in the multi-check sample) instead of the multi-check drop-down. By clicking on one item in this drop-down, the grid content should be filtered using this selection. 

A code sample would be greatly appreceated. 

I'm using Kendo.Mvc Version 2018.2.516.545

Thank you and regards

Daniel 

6 Answers, 1 is accepted

Sort by
0
Marin Bratanov
Telerik team
answered on 24 Jul 2018, 11:00 AM
Hello Daniel,

You can use the basic approach from this demo: https://demos.telerik.com/aspnet-mvc/grid/filter-menu-customization. It shows how you can create custom UI for the filter menu which for the City column is a dropdown that takes its data from its own action, so you can provide the desired distinct values.

You can also take the approach from this therad where you can use the change event of the dropdown to filter the grid data source immediately: https://www.telerik.com/forums/filtering-from-a-drop-down-list.

Here is the modified view of the demo that incorporates this:

@(Html.Kendo().Grid<Kendo.Mvc.Examples.Models.EmployeeViewModel>()   
    .Name("Grid")
    .Columns(columns => {
        columns.Template(@<text>@item.FirstName  @item.LastName</text>)
                .ClientTemplate("#=FirstName# #=LastName#")
                .Title("Name");
        columns.Bound(e => e.City)
                .Filterable(filterable => filterable.UI("cityFilter"))
                .Width(200);
        columns.Bound(e => e.Title)
                .Filterable(filterable => filterable.UI("titleFilter"))
                .Width(350);  
    })   
    .Filterable(filterable => filterable
        .Extra(false)
        .Operators(operators => operators
            .ForString(str => str.Clear()
                .StartsWith("Starts with")
                .IsEqualTo("Is equal to")
                .IsNotEqualTo("Is not equal to")
            ))
        )  
    .DataSource(dataSource => dataSource
        .Ajax()
        .Read(read => read.Action("FilterMenuCustomization_Read", "Grid"))
     )
)
 
<script type="text/javascript">
    function cityFilter(element) {
        element.kendoDropDownList({
            dataSource: {
                transport: {
                    read: "@Url.Action("FilterMenuCustomization_Cities")"
                }
            },
            change: function (evt) {
                var value = this.value();
                var grid = $("#Grid");
                if (value) {
                    grid.data("kendoGrid").dataSource.filter({ field: "City", operator: "eq", value: value });
                } else {
                    grid.data("kendoGrid").dataSource.filter({});
                }
            },
            optionLabel: "--Select City--"
        });
    }
 
    function titleFilter(element) {
        element.kendoAutoComplete({
            dataSource: {
                transport: {
                    read: "@Url.Action("FilterMenuCustomization_Titles")"
                }
            }
        });
    }
</script>


You can even customize thie particular menu by walking the DOM, adding classes and hiding other elements, for example this will hide the Clear and Filter buttons:

<style>
    .hiddenFilterElems .k-button {display: none;}
</style>
<script type="text/javascript">
    function cityFilter(element) {
        element.parents("form").first().addClass("hiddenFilterElems");
        element.kendoDropDownList({

 

Regards,
Marin Bratanov
Progress Telerik
Try our brand new, jQuery-free Angular components built from ground-up which deliver the business app essential building blocks - a grid component, data visualization (charts) and form elements.
0
Daniel
Top achievements
Rank 1
answered on 26 Jul 2018, 02:34 PM

Hi Marin

thank you for your answer and for your code sample. What I'd like to omit is the roundtrip to the server (see e.g. the code "read: "@Url.Action("FilterMenuCustomization_Cities")"" in your sample. What I'd like to do is to access the list of possible row values in the corresponding column which the user wants to filter. Please see the "server operations" sample in https://demos.telerik.com/aspnet-mvc/grid/filter-multi-checkboxes, when you click the City-filter, a list of distinct cities appear... this is the list I am talking about... Is it possible to access this list in the "function  cityFilter(element)"-function? 

Thank you again for your help and best regards.

Daniel 

0
Marin Bratanov
Telerik team
answered on 27 Jul 2018, 01:05 PM
Hi Daniel,

When having server operations, both having all distinct values from the data source, and not having a separate request is a self-contradicting scenario because the client cannot know what data there is in the actual data source, it only has the current page.

If you are OK with having the dropdown use only the current data in the grid (after filtering by city you will only have data for that city, so the dropdown will only have 1 option), you can do something like this: https://dojo.telerik.com/@bubblemaster/oCeYuNEP. This can work best if there is no editing in the grid and this example does not use server operations. If this suits your needs, you can use the snippet below to translate it to the MVC wrapper.
If you have editing in the grid, you'd need to hook to the filterMenuOpen  event and do a setDataSource() on the dropdown to update with new data or remove old values.

Below is a sample implementation that steps on the initial grid data source that you can also use as base in case defining separate data sources is not an option. Storing the data source in a data object in the grid wrapper is not the best solution, so I am leaving it up to you to determine where you can store data in such a case (even a global variable is an option).

The key point is setting the dataSource of the dropdown to a suitable data source. The exapmle above shows one way to fetch it from the grid. The example below shows another. You can use a separate data source control or call your own service once to populate an array when the grid loads - the menu uses lazy initialization so it will be created when shown only.

I hope this information helps you choose the best approach for your case and needs.

@(Html.Kendo().Grid<Kendo.Mvc.Examples.Models.EmployeeViewModel>()
    .Name("Grid")
    .Events(ev => ev.DataBound("storeData"))
    .Columns(columns =>
    {
        columns.Template(@<text>@item.FirstName  @item.LastName</text>)
                                        .ClientTemplate("#=FirstName# #=LastName#")
                                        .Title("Name");
                columns.Bound(e => e.City)
        .Filterable(filterable => filterable.UI("cityFilter"))
        .Width(200);
                        columns.Bound(e => e.Title)
        .Filterable(filterable => filterable.UI("titleFilter"))
        .Width(350);
    })
    .Filterable(filterable => filterable
        .Extra(false)
        .Operators(operators => operators
            .ForString(str => str.Clear()
                .StartsWith("Starts with")
                .IsEqualTo("Is equal to")
                .IsNotEqualTo("Is not equal to")
            ))
        )
    .DataSource(dataSource => dataSource
        .Ajax()
        .Read(read => read.Action("FilterMenuCustomization_Read", "Grid"))
        )
)
 
<style>
    .hiddenFilterElems .k-button {
        display: none;
    }
</style>
<script type="text/javascript">
    function cityFilter(element) {
        element.parents("form").first().addClass("hiddenFilterElems");
        element.kendoDropDownList({
            dataSource: $("#Grid").data("origData"),
            change: function (evt) {
                var value = this.value();
                var grid = $("#Grid");
                if (value) {
                    grid.data("kendoGrid").dataSource.filter({ field: "City", operator: "eq", value: value });
                } else {
                    grid.data("kendoGrid").dataSource.filter({});
                }
            },
            optionLabel: "--Select City--",
            dataTextField: "City",
            dataValueField: "City"
        });
    }
 
    function storeData(e) {
        var gridData = e.sender.dataSource.data();
        var uniqueDsResult = removeDuplicates(e.sender.dataSource.data(), "City");
        e.sender.element.data("origData", uniqueDsResult);
    }
 
    function titleFilter(element) {
        element.kendoAutoComplete({
            dataSource: {
                transport: {
                    read: "@Url.Action("FilterMenuCustomization_Titles")"
                }
            }
        });
    }
 
    function removeDuplicates(items, field) {
        var getter = function (item) { return item[field] },
            result = [],
            index = 0,
            seen = {};
 
        while (index < items.length) {
            var item = items[index++],
                text = getter(item);
 
            if (text !== undefined && text !== null && !seen.hasOwnProperty(text)) {
                result.push(item);
                seen[text] = true;
            }
        }
 
        return result;
    }
</script>

 


Regards,
Marin Bratanov
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.
0
Daniel
Top achievements
Rank 1
answered on 02 Aug 2018, 08:02 AM

Hi Marin

Thank you for providing your suggestions. Yes, I want to use the current data in the grid, and it is a simple no editing scenario. Following your dojo sample, I tried to slim down the filter dialog: no extra filter, only eq: string operator, no Filter and Clear buttons. Furthermore, I replaced the kendoDropdownList with a simple kendoListBox. The plan is, as soon as an item in this listBox is selected (using the change: event), the grid should be filtered by applying this filter. Please have a look at https://dojo.telerik.com/umAFOJUK, there you'll find my work so far. The problem is: as soon as I click on the city filter button, an exception is thrown and the change: event is never fired.

kendo.all.js:9555 Uncaught TypeError: e.value is not a function
    at init.refresh (VM14497 kendo.all.min.js:29)
    at init.bind (VM14497 kendo.all.min.js:29)
    at r.applyBinding (VM14497 kendo.all.min.js:29)
    at r.bind (VM14497 kendo.all.min.js:29)
    at s (VM14497 kendo.all.min.js:28)
    at s (VM14497 kendo.all.min.js:28)
    at s (VM14497 kendo.all.min.js:28)
    at Object.a [as bind] (VM14497 kendo.all.min.js:28)
    at init.refresh (VM14497 kendo.all.min.js:48)
    at init._init (VM14497 kendo.all.min.js:48)

 

How can I correct this error? 

Thank you again for your help and best regards.

Daniel

0
Accepted
Konstantin Dikov
Telerik team
answered on 06 Aug 2018, 07:24 AM
Hello Daniel,

The ListBox does not have "value" method, which is mandatory for the filter elements. As a workaround you could try to render the ListBox over another element and handle its change event to manually filter the Grid. Following is the modified dojo example, which renders the ListBox:

Best Regards,
Konstantin Dikov
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.
0
Daniel
Top achievements
Rank 1
answered on 08 Aug 2018, 01:07 PM

Hi Konstantin

Thank you very much for your help. Your dojo-sample did the trick...

I added some additional functionality like sort the kendoListBox's dataSource and caching all the individual column values for further use. 

Best regards and thank's again!

Daniel 

 

 

Tags
Grid
Asked by
Daniel
Top achievements
Rank 1
Answers by
Marin Bratanov
Telerik team
Daniel
Top achievements
Rank 1
Konstantin Dikov
Telerik team
Share this question
or