【问题标题】:Kendo Jquery Grid - Filtering on comma separated values columnKendo Jquery Grid - 过滤逗号分隔值列
【发布时间】:2019-05-28 03:14:05
【问题描述】:

我们有一个 Kendo Jquery Grid,我们正在尝试在 Column 上提供过滤器,我们以逗号分隔的形式显示值。代码如下所示,我试图在 dataBound 事件中捕获过滤器对象并尝试过滤掉数据源上的记录,但无济于事。请建议我们如何实现这一目标。

我们需要实现的领域是ProviderSpecialty

<script>
    var grid;
    var dataSource;
    var gridView = 'updatesRequired';

    $(document).ready(function () {
        $('#selectGridView').change(function () {
            gridView = $('#selectGridView').val();
            $('#grid').kendoGrid('destroy').empty();
            renderGrid();
        });
        renderGrid();
    });

    function renderGrid() {

        var fieldsSchema =
        {
            'ProviderDelegateId': { type: 'number' },
            'EndDate': {type: 'date' }
        };
        dataSource = new kendo.data.DataSource({
            transport: {
                read: {
                    url: providerProfileApiBaseUrl)
                }
            },
            error: function (e) {
                if (e.xhr.responseText != '') {
                    var jsonError = JSON.parse(e.xhr.responseText);

                    if (myApp.Web.utility.displacolumns !== undefined) {
                        myApp.Web.utility.displacolumns.push({
                            field: 'EndDate', template: '#= kendo.toString(kendo.parseDate(EndDate), "MM/dd/yyyy")#', title: 'Campaign End Dt', width: '125px', filterable: {
                                ui: function (element) {
                                    element.kendoDatePicker({
                                        format: "MM/dd/yyyy"
                                    });
                                }
                            }
                        });
                    }
                    myApp.Web.utility.displayErrorDialog(jsonError.error);
                }
            },
            pageSize: myApp.Web.config.grid.pageable.pageSize,
            schema: {
                model: {
                    id: 'UniqueId',
                    fields: fieldsSchema
                }
            },
            sort: { field: "ProviderLastName", dir: "asc" }
        });

        var columns = [];
        columns.push({ field: 'ProviderDelegateId', hidden: true });
        if (gridView === 'updatesRequired') {
            columns.push({ field: 'ProviderLastName', title: 'Last Name', width: '125px', template: '<a href="/ProviderLanding/ProviderUpdate/Index/#=CampaignTrackingId#">#=ProviderLastName#</a>' });
            columns.push({ field: 'ProviderFirstName', title: 'First Name', width: '125px', template: '<a href="/ProviderLanding/ProviderUpdate/Index/#=CampaignTrackingId#">#=ProviderFirstName#</a>' });
            columns.push({ field: 'ProviderNPI', title: 'NPI', width: '125px', template: '<a href="/ProviderLanding/ProviderUpdate/Index/#=CampaignTrackingId#">#=ProviderNPI != null ? ProviderNPI : \'\' #</a>' });
        } else {
            columns.push({ field: 'ProviderLastName', title: 'Last Name', width: '125px', template: '<a href="/ProviderUpdate/UpdateProfile?providerId=#=ProviderId#">#=ProviderLastName#</a>' });
            columns.push({ field: 'ProviderFirstName', title: 'First Name', width: '125px', template: '<a href="/ProviderUpdate/UpdateProfile?providerId=#=ProviderId#">#=ProviderFirstName#</a>' });
            columns.push({ field: 'ProviderNPI', title: 'NPI', width: '125px', template: '<a href="/ProviderUpdate/UpdateProfile?providerId=#=ProviderId#">#=ProviderNPI != null ? ProviderNPI : \'\' #</a>' });
        };
        columns.push({ field: 'ProviderSpecialty', title: 'Specialty', width: '125px', template: '#= getSpecialties(ProviderSpecialties) #' });
        columns.push({ field: 'ProviderEmail', title: 'Email', width: '125px' });
        columns.push({ field: 'LocationName', title: 'Location', width: '125px', template: '#= getLocations(ProviderLocations) #'  });
        if (gridView === 'updatesRequired') {
            columns.push({ field: 'CampaignName', title: 'Campaign', width: '125px', template: '<a href="/ProviderLanding/ProviderUpdate/Index/#=CampaignTrackingId#">#=CampaignName#</a>' });
            columns.push({
                field: 'EndDate', template: '#= kendo.toString(kendo.parseDate(EndDate), "MM/dd/yyyy")#', title: 'Campaign End Dt', width: '125px', filterable : {
                ui: function (element) {
                    element.kendoDatePicker({
                        format: "MM/dd/yyyy"
                    });
                }
            } });
        } else {
            columns.push({ field: 'IsPendingChangeAvailable', title: 'Pending Changes', width: '125px', template: '#if (IsPendingChangeAvailable) {# Yes #} else {# No #}#' });
        };

        grid = $("#grid").kendoGrid({
            dataSource: dataSource,
            columns: columns,
            scrollable: false,
            filterable: myApp.Web.config.grid.filterable,
            sortable: myApp.Web.config.grid.sortable,
            pageable: myAppWeb.config.grid.pageable,
        }).data('kendoGrid');
    };

    function getSpecialties(specialties) {
        // remove duplicates and then join...
        var result = [];
        $.each(specialties, function(i, e) {
            if ($.inArray(e.SpecialtyName, result) == -1) result.push(e.SpecialtyName);
        });
        return result.join(',');
    };

    function getLocations(locations) {
        return locations.map(function (location) {
            return location.LocationName
        }).join(',');
    };

    $(document).ajaxStart(function () {
        $('#overlay-screen').show();
    });
    $(document).ajaxStop(function () {
        $('#overlay-screen').hide();
    });
</script>

【问题讨论】:

    标签: jquery jquery-ui filter kendo-ui kendo-grid


    【解决方案1】:

    过滤框不允许您添加逗号。我不确定您是否可以使用逗号来执行此操作,除非您覆盖 UI 以显示您自己的过滤器框并在更改时通过 jquery/javascript 应用过滤器,如下所示。如果我理解正确的话。

    //After user enters their values. Imagine "Tom,John" would be what the user entered
    //After you exploded the comma list yourself
    $('#grid').data('kendoGrid').dataSource.filter({
        logic: "or",
        filters: [
           { field: "Name", operator: "contains", value: 'Tom' },
           { field: "Name", operator: "contains", value: 'John' },
        ]
    });
    

    显然,如果您也允许过滤其他列,那会更高级一些。相反,您将修改过滤器而不是覆盖它们。请注意,我的示例使用包含。如果你想要的话,这可能是 eq。但是,假设您要过滤的列是文本,您可以在可过滤对象上使用“mulit: true”。这允许用户使用 kendo 的 UI 元素管理选择

    //On the column property
    filterable: {
        multi:true
    }
    

    这将为您提供列中每个可能值的复选框。请注意,如果您将网格的可过滤对象上的模式设置为行。这行不通

    //On the grid
    filterable: {
        mode: "row"
    }
    

    从 dojo 中的以下链接打开代码 https://docs.telerik.com/kendo-ui/api/javascript/ui/grid/configuration/columns.filterable.multi

    希望对你有帮助

    【讨论】:

      【解决方案2】:

      这个问题可以通过在三个地方改变网格的默认行为来解决。

      1.更改给定列的配置

      向列可过滤配置添加一个附加属性,以指示应应用特殊逻辑。 column.filterable = { multi: true, isCommaSeparatedList: true}

      2。在过滤器菜单初始化期间更改多选的数据源(filterMenuInit 事件)
      从网格列集合中获取列,并检查可过滤对象是否包含用户定义的属性“isCommaSeparatedList”。

       filterMenuInit(event: kendo.ui.GridFilterMenuInitEvent) {
              const field = event.field;
      
              //Get the column where the user wants to set the filter
              filteredColumn = event.sender.columns.filter((column) => { return column.field === field })[0] as kendo.ui.GridColumn;
              if (filteredColumn && typeof filteredColumn.filterable === "object" && filteredColumn.filterable["isCommaSeparatedList"]) {
      
                  //Declare an array to hold the unique select items
                  var selectItems = new Array();
      
                  //Declare an dictionary for fast lookup
                  var valuesDictionary = new Object();
      
                  //Get the data from the grid
                  const gridRecords = event.sender.dataSource.data().toJSON();
      
                  //Loop the records an find the individual values in the comma separated list
                  for (let gridRecord of gridRecords) {
                      const values = gridRecord[field].toString().split(",") as Array<string>;
                      values.forEach((value) => {
                          value = value.trim();
                          //If the value is not found in the dictionary then the value is added to the dictionary and the selectItems Array
                          if (!valuesDictionary[value]) {
                              valuesDictionary[value] = true;
                              selectItems.push({ [field]: value });
                          }
                      });
                  }
      
                  //Sort the selectItems
                  selectItems.sort((a, b) => {
                      if (a[field] < b[field]) return -1;
                      else if (a[field] > b[field]) return 1;
                      return 0;
                  });
      
                  //Set the datasource for the multi select column to the items found
                  const filterable = filteredColumn.filterable as any as kendo.ui.GridColumnFilterable;
                  filterable.dataSource.data(selectItems);
              }
      

      3.当用户选中或取消选中一项或多项时更改过滤器(过滤器事件)
      如果一列的可过滤属性设置为{multi: true},那么当通过选中或取消选中过滤器菜单中的复选框来更改过滤器时,将导致过滤器的运算符设置为“eq”。这不是我们想要的。因为底层数据源包含一个逗号分隔的列表。所以我们希望运算符是“包含”的。我使用的技巧是在网格“过滤器”事件中复制过滤器表达式。我遍历应用于给定列的所有过滤器并添加相同的过滤器,但使用 operator = "contains"

             filter: (event: kendo.ui.GridFilterEvent) => {
                  //This function is called each time the filter in the grid is changed.
                  if (event.filter) {
                      //Try to get the column definition from the columns dictionary for the column where the filter has changed.
                      const column = event.sender.columns.filter((column) => { return column.field === event.field })[0] as kendo.ui.GridColumn;
      
                      //Find out if the filterable property of the column is set to an object and if the object has a property "isList"
                      if (column && column.filterable && typeof column.filterable === "object" && column.filterable["isCommaSeparatedList"]) {
                          //Duplicate all the filters with an operator = "eq" to a filter with operator = "contains"
                          for (let filter of event.filter.filters) {
                              if (filter.operator === "eq" && !filter["handled"]) {
                                   //Add a handled property to check if the filter has already been duplicated to prevent an endless loop
                                  filter["handled"] = true;
                                  event.filter.filters.push({ value: filter.value, operator: "contains", field: filter.field });
                              }
                          }
                      }
                  }
              }
      

      希望这对你有用

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-09-27
        • 2020-10-20
        • 2022-01-25
        • 1970-01-01
        • 2021-11-19
        • 2014-02-18
        • 2016-06-15
        • 2015-08-24
        相关资源
        最近更新 更多