You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修改Kendo Grid代码实现类Excel的动态列筛选功能

Kendo Grid实现DeptName列的动态筛选(类Excel效果)

当前现状

我们的Kendo Grid能基于各列筛选条件展示过滤后的结果,但列筛选下拉列表始终显示该列的全部原始选项,不会排除已经被其他列筛选过滤掉的项。我们需要实现类似Excel的动态筛选——筛选下拉列表的选项会随其他列已应用的筛选自动更新,只保留当前网格中存在的唯一值。

技术问题

如何修改Kendo代码,让DeptName列的筛选下拉仅显示当前网格数据中的唯一值,同时自动适配其他列已应用的所有筛选条件?

现有代码

function BindGrid() {
    var grid = new kendo.data.DataSource({
        transport: {
            read: function (options) {
                $.ajax({
                    type: "GET",
                    url: "Spartan2PHQDataGrid.aspx/GetPHQGridData",
                    data: "",
                    contentType: "application/json; charset=utf-8",
                    dataType: "json",
                    success: function (response) {
                        options.success(JSON.parse(response.d));
                    }
                });
            }
        },
        schema: {
            model: {
                fields: {
                    //Format: { editable: true},
                    //AdType: { editable: true},
                    //ShortDescription: { editable: true},
                    //PrintQty: { editable: true},
                }
            }
        },
        pageSize: 10,
    });

    kGrid = $("#Grid").kendoGrid({
        toolbar: "<input type='button' class='k-button' onclick='SaveClicked(this)' value='Save'/>&nbsp;&nbsp;<input type='button' class='k-button' onclick='refreshGrid()'  value='Cancel'/>",
        dataSource: grid,
        scrollable: true,
        filterable: {
            extra: false,
            operators: {
                string: {
                    startswith: "Starts with",
                    eq: "Is equal to",
                    neq: "Is not equal to"
                }
            }
        },
        sortable: true,
        resizable: true,
        reorderable: true,
        pageable: {
            alwaysVisible: true,
            pageSizes: [10, 20, 50, 100]
        },
        editable: true,
        columns: [
            {
                field: "Id", title: "Id", hidden: true,
                headerAttributes: {
                    "class": "grid-header"
                }
            },
            {
                title: "select_all", width: "70px",
                headerTemplate: "<input type='checkbox' id='header-chb' onclick='checkAllClick($(this))' class='k-checkbox header-checkbox'>",
                headerAttributes: {
                    "class": "grid-header check-header"
                },
                attributes: {
                    "class": "checkbox-cell",
                },
                template: "<input type=\"checkbox\" class=\"row-checkbox\" />",                
            },
            {
                field: "DeptName", title: "Dept", width: "100px", editable: true,
                headerAttributes: {
                    "class": "grid-header"
                }, filterable: {
                    multi: true,
                    search: true
                }
            },
            {
                field: "UPC", title: "UPC", width: "120px", filterable: true, editable: true,
                headerAttributes: {
                    "class": "grid-header"
                }
            },
            {
                field: "BrandName", title: "Brand", width: "120px", filterable: true, editable: true,
                headerAttributes: {
                    "class": "grid-header"
                }
            },
            {
                field: "ShortDescription", title: "Description", width: "180px", editable: false,
                headerAttributes: {
                    "class": "grid-header"
                }
            },
            {
                field: "Headline", title: "Headliner", width: "150px", editable: false,
                headerAttributes: {
                    "class": "grid-header"
                }
            },
            {
                field: "AdStartDate", title: "Effective Date", width: "140px", editable: true,
                headerAttributes: {
                    "class": "grid-header"
                }, format: "{0: MM/dd/yyyy}", type: "date",
                filterable: {
                    ui: "datetimepicker"
                },
            },
            {
                field: "Format", title: "Format", width: "110px", filterable: true, editable: false,
                headerAttributes: {
                    "class": "grid-header"
                }, filterable: {
                    multi: true,
                    search: true
                }
            },
            {
                field: "PrintQty", title: "Qty", width: "80px", editable: false,
                headerAttributes: {
                    "class": "grid-header"
                }
            },
            {
                field: "AdType", title: "AdType", width: "100px", filterable: true, editable: false,
                headerAttributes: {
                    "class": "grid-header"
                }
            },
            {
                field: "SaleType", title: "Sale Type", width: "100px", filterable: true, editable: false,
                headerAttributes: {
                    "class": "grid-header"
                }
            },            
        ]                       
    }).data("kendoGrid");
}

尝试的无效代码

filterMenuInit: function (e) {
    var filteredDeptNames = getFilteredDeptNames(this);
    var filterMenu = e.container.find("[data-field='DeptName'] .k-filter-menu");
    if (filterMenu.length > 0) {
        var dropdownlist = filterMenu.data("kendoDropDownList");
        if (dropdownlist) {
            dropdownlist.dataSource.data(filteredDeptNames);
            dropdownlist.refresh();
        }
    }
},

问题分析与解决方案

之前的代码无效原因:

  • filterMenuInit仅在筛选菜单第一次初始化时触发,后续其他列筛选后不会重新执行,无法更新下拉选项
  • DOM选择器定位错误,应该直接通过e.field判断当前打开的是哪列的筛选菜单

正确的实现方式是使用filterMenuOpen事件(每次打开筛选菜单时触发),实时基于当前已过滤的数据源生成唯一的DeptName选项:

修改后的完整代码(关键部分)

在Grid配置中添加filterMenuOpen事件,并实现对应的处理函数:

kGrid = $("#Grid").kendoGrid({
    // 保留原有配置...
    filterable: {
        extra: false,
        operators: {
            string: {
                startswith: "Starts with",
                eq: "Is equal to",
                neq: "Is not equal to"
            }
        }
    },
    // 添加filterMenuOpen事件
    filterMenuOpen: function(e) {
        // 仅处理DeptName列的筛选菜单
        if (e.field !== "DeptName") return;

        // 获取当前数据源经过所有筛选后的全部数据(注意:如果用服务器端分页/过滤,需调整为获取全量过滤后数据)
        var filteredData = this.dataSource.data();
        // 提取DeptName的唯一值,去重并排序
        var uniqueDepts = [];
        var seen = {};
        filteredData.forEach(function(item) {
            var dept = item.DeptName;
            if (dept && !seen[dept]) {
                seen[dept] = true;
                uniqueDepts.push({ value: dept, text: dept });
            }
        });
        uniqueDepts.sort(function(a, b) {
            return a.text.localeCompare(b.text);
        });

        // 获取筛选菜单中的多选下拉组件
        var multiSelect = e.container.find("[data-role='multiselect']").data("kendoMultiSelect");
        if (multiSelect) {
            // 更新下拉数据源
            multiSelect.dataSource.data(uniqueDepts);
            // 保留已选中的有效选项
            var selectedValues = multiSelect.value();
            if (selectedValues.length > 0) {
                multiSelect.value(selectedValues.filter(function(val) {
                    return seen[val];
                }));
            }
        }
    },
    // 保留原有配置...
}).data("kendoGrid");

核心逻辑说明

  1. 事件选择:用filterMenuOpen替代filterMenuInit,确保每次打开筛选菜单都能重新计算选项
  2. 获取过滤后的数据:通过this.dataSource.data()获取当前所有已过滤的数据(如果是服务器端分页/过滤,需在客户端缓存全量数据或从后端获取过滤后的全量列表)
  3. 去重处理:遍历数据提取唯一的DeptName值,整理成MultiSelect需要的{value:..., text:...}格式
  4. 更新下拉组件:找到对应列的MultiSelect组件,更新其数据源,并保留用户已选中的有效选项

内容的提问来源于stack exchange,提问作者Faizan Ali

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 02:09:52