【问题标题】:Apply grid filter programmatically from function从函数以编程方式应用网格过滤器
【发布时间】:2012-03-26 15:16:56
【问题描述】:

使用 Ext.ux.grid.FiltersFeature,我有远程过滤器,我正在尝试编写一个函数以编程方式在网格列上应用日期过滤器(而不是单击列标题中的过滤器下拉菜单)。我第一次运行该函数时,网格存储会在没有过滤器的情况下重新加载。当我第二次(以及之后的每次)运行该函数时,它工作得很好,商店重新加载了过滤器。这是我拥有的功能的要点:

// a filter object for testing
aFilter = {type: 'date', field: 'a_date_field', comparison: 'gt', value: '2012-03-08 00:00:00'}

var grid = Ext.create('Ext.grid.Panel', {
    store: store,
    features: [{
        ftype: 'filters',
    }],
    columns[{
        header: 'ID',
        dataIndex: 'id',
        itemId: 'id',            
        width: 40,
    }, {
        xtype: 'datecolumn',
        header: 'Date',
        dataIndex: 'a_date_field',
        itemId: 'a_date_field',
        width: 75,
        format:'j-M-Y',
        filterable: true
    }],
    listeners: {
        'afterrender': function() {

            // Need to create the filters as soon as the grid renders
            // rather than waiting for the user to click on the header
            grid.filters.createFilters();
        }
    },
    bbar: [{
        text: 'Do a filter',
        handler: function() {

            // get the filter that is attached to the grid
            var gridFilter = grid.filters.getFilter(aFilter.field);

            // have to do this to create a menu for this filter
            gridFilter.init({dataIndex: aFilter.field, type: aFilter.type, active: true});

            // if this column is a date filter column
            if (gridFilter.type == 'date') {
                var dateValue = Ext.Date.parse(aFilter.value, 'Y-m-d H:i:s');
                if (filter.comparison == 'gt') {
                    gridFilter.setValue({after: dateValue});
                } else {
                    gridFilter.setValue({before: dateValue});
                }
            }
        }
    }
});

我还发现,如果我在运行该函数之前单击 any 网格标题菜单,则此函数第一次起作用。

我一直在尝试找出在第一次尝试失败后对网格进行了哪些更改以使过滤器工作,或者单击 any 网格标题如何使其工作。但是我添加的任何内容似乎都无法修复它,因此它将第一次运行。有人成功实现了吗?

【问题讨论】:

  • 你试过在FiltersFeature对象上调用createFilter()吗?

标签: extjs filter grid extjs4


【解决方案1】:

在源码中,可以看到与此相关的评论。

// Call getMenu() to ensure the menu is created, and so, also are the filters. We cannot call
// createFilters() withouth having a menu because it will cause in a recursion to applyState()
// that ends up to clear all the filter values. This is likely to happen when we reorder a column
// and then add a new filter before the menu is recreated.
me.view.headerCt.getMenu();

您可以在应用过滤器之前测试菜单是否已创建。如果没有,请自己做。

if(!grid.getView().headerCt.menu){
    grid.getView().headerCt.getMenu();
}

【讨论】:

    【解决方案2】:

    只需添加

    filter: true
    

    到网格列描述如下:

    me.columns = [
            {header:"Name", dataIndex:"name", editor:"textfield", filter: true},
        ];
    

    如果您想在第一次尝试后让过滤器工作,请先创建实例。

    【讨论】:

      【解决方案3】:

      作为更新,我扩展了这个函数并修改它以使用 ExtJS 4.1.1

      这是动态设置网格过滤器的功能示例(用户无需单击菜单项)。之后,过滤的项目将在网格列标题菜单中对用户可见,就像他单击它们并手动设置它们一样。

      “grid”参数是您要过滤的带有FiltersFeature 的网格。另一个参数是“过滤器”对象的数组(我将在下面展示一个示例),该函数只是将所有传递的“过滤器”对象应用于网格。

      doGridFilter: function(grid, filters) {
      
          // for each filter object in the array
          Ext.each(filters, function(filter) {
              var gridFilter = grid.filters.getFilter(filter.field);
      
              gridFilter.setActive(true);
              switch(filter.data.type) {
      
                  case 'date':
                      var dateValue = Ext.Date.parse(filter.data.value, 'm/d/Y'),
                          value;
      
                      switch (filter.data.comparison) {
      
                          case 'gt' :
                              value = {after: dateValue};
                              break;
                          case 'lt' :
                              value = {before: dateValue};
                              break;
                          case 'eq' :
                              value = {on: dateValue};
                              break;
                      }
                      gridFilter = log.filters.getFilter(filter.field);
                      gridFilter.setValue(value);
                      gridFilter.setActive(true);
                      break;
      
                  case 'numeric':
                      var value;
      
                      switch (filter.data.comparison) {
      
                          case 'gt' :
                              value = {gt: filter.data.value};
                              break;
                          case 'lt' :
                              value = {lt: filter.data.value};
                              break;
                          case 'eq' :
                              value = {eq: filter.data.value};
                              break;
                      }
                      gridFilter = log.filters.getFilter(filter.field);
                      gridFilter.setValue(value);
                      gridFilter.setActive(true);
                      break;
      
                  case 'list':
                      gridFilter = log.filters.getFilter(filter.field);
                      gridFilter.menu.setSelected(gridFilter.menu.selected, false);
                      gridFilter.menu.setSelected(filter.data.value.split(','), true);
                      break;
      
                  default :
                      gridFilter = log.filters.getFilter(filter.field);
                      gridFilter.setValue(filter.data.value);
                      break;
              }
          });
      }
      

      这是一个“过滤器”对象数组的示例。

      // an example of a "filters" argument
      [{
          field: 'some_list_column_data_index',
          data: {
              type: 'list',
              value: 'item1,item2,item3,item4,item5,item6,item7'
          }
      }, {
          field: 'some_date_column_data_index',
          data: {
              type: 'date',
              comparison: 'gt',
              value: '07/07/2007'
          }
      }]
      

      需要注意的是,您需要在使用此功能之前手动“创建”过滤器。通常FiltersFeature 网格过滤器是在用户第一次单击其中一个时“创建”的,如果用户只想应用其中一个预定义过滤器,则可能不会发生这种情况。

      这可以通过在网格面板中包含这个 afterrender 侦听器来轻松处理。

      listeners: {
      
          // must create the filters after grid is rendered
          afterrender: function(grid) {
              grid.filters.createFilters();
          }
      }
      

      【讨论】:

      • 我正在使用 4.1 和 4.2 以下返回错误“filter.data.value.split(',') //不是函数” - filter.data.value 似乎工作得很好靠自己
      【解决方案4】:

      我发现了另一种实现方式。似乎只有在渲染网格后才将网格特征绑定到网格。这意味着过滤器的任何设置在渲染网格之前都不会生效。商店的初始加载似乎是在呈现网格之前启动的。

      我通过使用不包含数据的内存代理创建存储解决了我的问题。

      me.store = Ext.create('Ext.data.Store', {
          model: 'SummaryData',
          data: [],
          proxy: {
              type: 'memory',
              reader: 'array'
          },
          remoteSort: true,
          remoteFilter: true
      });
      

      然后在网格上设置一个afterrender 处理程序以插入正确的代理并启动存储的加载。

      afterrender: function () {
          var me = this;
      
          me.store.setProxy({
              type: 'ajax',
              url : '/print_unallocated/change_site__data',
              reader: {
                  type: 'json',
                  root: 'rows'
              },
              listeners: {
                  exception: function (proxy, response) {
                      Max.reportException(response);
                  }
              }
          });
      
          me.filters.createFilters();
          me.store.load();
      },
      

      【讨论】:

        【解决方案5】:

        您想应用网格过滤器还是 store.filter() 功能更适合您?在这种情况下只需过滤商店,网格将显示过滤后的记录。

        【讨论】:

        • 用户在应用此过滤器后会继续以其他方式过滤网格,因此我需要保持网格标题与过滤器同步。
        【解决方案6】:

        我有解决方法:

        bbar: [{
            text: 'Do a filter',
            handler: function() {
                var grid = this.up('grid');
                var dateValue = Ext.Date.parse(aFilter.value, 'Y-m-d H:i:s');
                var value = aFilter.comparison == 'gt' ? {after: dateValue} : {before: dateValue};
        
                var gridFilter = grid.filters.getFilter(aFilter.field);
        
                if (!gridFilter) {
                    gridFilter = grid.filters.addFilter({
                        active: true,
                        type: aFilter.type,
                        dataIndex: aFilter.dataIndex,
                    });
        
                    gridFilter.menu.show();
                    gridFilter.setValue(value);
                    gridFilter.menu.hide();
                } else {
                    gridFilter.setActive(true);
                }
        
                Ext.Function.defer(function(){
                    gridFilter = grid.filters.getFilter(aFilter.field);
                    gridFilter.setValue(value);
                }, 10);
            }
        }]
        

        如您所见,我实际上应用了 2 次过滤器。

        【讨论】:

        • 哇@Lolo 您是如何获得应用过滤器两次解决方案的?是否存在针对它的错误?
        • @DmitryB 在第二次单击按钮后,我来到了它工作的地步。因此,下一个明显的步骤是尝试立即进行。我不知道这是否是一个错误,可能是。设置该值会导致访问菜单,因此必须呈现它。最后,在我看来,第一次 setValue 调用(在 if 中)是不必要的
        • 我目前正在使用 4.1.1,似乎使用 Ext.Function.defer 是多余的:它们的关键似乎是调用 filter.setValue 两次,重要的是,更新 filter 句柄之间,即filter = grid.filters.getFilter(..)(这是一个错误吗?)
        • 两次设置该值是相当hacky。只需确保网格视图的header menu has been initialized
        【解决方案7】:

        这里有一些值得研究的东西。过滤器插件似乎正在侦听 menucreate 事件以初始化过滤器。我想知道菜单创建事件是否被推迟到必要时,因此过滤器没有被初始化?

        /**
         * @private Handle creation of the grid's header menu. Initializes the filters and listens
         * for the menu being shown.
         */
        onMenuCreate: function(headerCt, menu) {
            var me = this;
            me.createFilters(); //<------
            menu.on('beforeshow', me.onMenuBeforeShow, me);
        },
        

        【讨论】:

        • 感谢 Dmitry,我确实尝试过手动运行它,但似乎没有成功。在将它附加到此处后,我还触发了 beforeshow 事件,但没有运气。不过,它在菜单上出现了问题,按照 Lolo 的建议进行物理显示和隐藏。
        猜你喜欢
        • 2015-11-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-05-18
        • 1970-01-01
        • 1970-01-01
        • 2011-07-12
        • 2015-03-13
        相关资源
        最近更新 更多