如何将过滤器功能应用于 ExtJS6 中本地(内存)存储的分页网格?

How to apply filter function to paging grid with local(memory) store in ExtJS6?

我有一个带有本地商店的分页网格,我想使用我自己的函数应用一个过滤器。但是失败了。

根据互联网推荐,我在商店配置中使用了 remoteFilter: trueenablePaging: true 选项。

如果我用特定的配置对象过滤商店,它会完美地工作:

store.filter([{ property: 'age', value: 12 }]);

不幸的是,建立复杂的过滤条件是不够的。

根据documentation,store对象中有一个特殊的filterBy方法来使用function作为过滤器。但是,当我这样提供时:

store.filterBy( function( record ) {
  return record.get( 'age' ) <= 12;
});

我收到一个错误 Uncaught Error: Unable to use a filtering function in conjunction with remote filtering.

这是我在 fiddle https://fiddle.sencha.com/#fiddle/2u8l

中的工作示例

这是我的商店配置和来自控制器的所有业务逻辑。我将在此处跳过视图配置以专注于代码的主要部分(IMO)

Ext.define('TestGridViewModelr', {
    extend: 'Ext.app.ViewModel',

    alias: 'viewmodel.myexmpl.main.testgrid',

    data: {
    },
    formulas: {},
    stores: {
        simpsons: {
            model: 'Ext.data.Model',// 'SimpsonModel',
            pageSize: 2,
            // remoteSort: true,
            remoteFilter: true,
            proxy: {
                type: 'memory',
                enablePaging: true,
                reader: {
                    type: 'json',
                    rootProperty: 'items'
                }
            }
        }
    }

});

Ext.define('TestGridController', {
    extend: 'Ext.app.ViewController',

    alias: 'controller.myexmpl.main.testgrid',

    init: function () {
        console.log('controller inititalized\n  init async store loading...');
        setTimeout( this.onStoreLoad.bind( this ), 1000 );
    },

    initViewModel: function(vm){
        console.log( 'viewModel init', vm.get('test') );
    },
    emptyMethod: function () {},

    onStoreLoad: function () {
        console.log('loading store');
        var vm = this.getViewModel();
        var store = vm.getStore('simpsons');
        store.getProxy().data = this.getSimpsonsData().items;
        store.reload();
        // store.loadData( this.getSimpsonsData() );
    },

   //++++++++++++  FILTERING  ++++++++
    /* NO PROBLEM */
    onToggleFilter: function () {
        console.log('simple filter');
        var filter = this.getSimpleFilter()
        this.toggleFilter( filter );
    },
    /* PROBLEM */
    onToggleFnFilter: function(){
       console.log('function filter');
    //   var filterFn = this.filterChildren;
       var filterFn = this.getFilterUtil()
       this.toggleFilter( filterFn );
    },

    /* NO PROBLEM */
    getSimpleFilter: function(){
        return {
            property: 'age',
            value: '12'
        };
    },

    /* PROBLEM */
    getFilterUtil: function() {
        return Ext.create( 'Ext.util.Filter', {
            filterFn: this.filterChildren
        })
    },

    filterChildren: function( record ) {
        var age = record.get( 'age' );
        console.log( 'filter record up to age:', age )// debugger;
        return parseInt( age ) <= 12;
    },

    toggleFilter: function( fltr ) {
        var store = this.getViewModel().getStore( 'simpsons' );
        var filters = store.getFilters();
        if ( filters.length > 0 ) {
            store.clearFilter();
        } else {
           this. applyFilterToStore( fltr, store );
        }
    },

    applyFilterToStore: function( filter, store ){
        var method = Ext.isFunction( filter ) || filter instanceof Ext.util.Filter
            ? 'filterBy'
            : 'setFilters';
        store[method]( filter );
    },



    getSimpsonsData: function(){
        return  {
            'items': [{
                'name': 'Lisa',
                'age': 12,
                "email": "lisa@simpsons.com",
                "phone": "555-111-1224"
            }, {
                'name': 'Bart',
                'age': 8,
                "email": "bart@simpsons.com",
                "phone": "555-222-1234"
            }, {
                'name': 'Homer',
                'age': 40,
                "email": "homer@simpsons.com",
                "phone": "555-222-1244"
            }, {
                'name': 'Marge',
                'age': 34,
                "email": "marge@simpsons.com",
                "phone": "555-222-1254"
            }]
        }
    }
});



总的来说,我希望能够以编程方式在本地商店的分页网格上设置过滤条件。函数允许我扩展过滤器功能并使用连接和查询构建灵活的逻辑表达式。例如:

name.lenght <= 4 &&  ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0)

提前谢谢你, A.

您不能在一个商店中同时使用 remoteFilterfilterBy。决定过滤器的逻辑应该在哪里 - 在 Client SideServer Side?

如果在 server side 上,将 remoteFilter 设置为 true 并使用带有额外参数的 filter 操作,您可以在服务器上捕获这些参数并执行过滤器。

如果在 client side 上,将 remoteFilter 设置为 false 并像附加的那样使用 filterBy 函数。

查看 fiddle 上的示例(我只是更改了一些内容):https://fiddle.sencha.com/#fiddle/2ua4&view/editor

我终于解决了这个问题!

在下一行的 onFilterEndUpdate 方法中提到的错误:

...
me.getFilters().each(function(filter) {
  if (filter.getInitialConfig().filterFn) {
    Ext.raise('Unable to use a filtering function in conjunction with remote filtering.');
  }
});
...

我已经在我的商店实体中覆盖了这个方法并注释掉了这些行。 我知道这不是最好的解决方案,但我找不到更好的解决方案。

这里是关于这个主题的完整解决方案:

  1. 使用 remoteFilter: trueenablePaging: true 选项配置商店:
{
 model: 'Ext.data.Model',
 pageSize: 2,
 remoteFilter: true,
 proxy: {
   type: 'memory',
   enablePaging: true,
   reader: {
     type: 'json'
   }
 }
}
  1. 使用 Proxy 而不是 loadData 方法将数据加载到存储中:
store.getProxy().data = this.getSimpsonsData().items;
store.reload();
  1. 在商店初始化后覆盖方法 onFilterEndUpdate 并注释掉提到的行,即:
onStoreLoad: function() {
...
  store.onFilterEndUpdate = this.onFilterEndUpdate.bind( store );
...
},

onFilterEndUpdate: function() {
  var me = this
    , suppressNext = me.suppressNextFilter
    , filters = me.getFilters(false);
  // If the collection is not instantiated yet, it's because we are constructing.
  if (!filters) {
    return;
  }
  if (me.getRemoteFilter()) {
    // me.getFilters().each(function(filter) {
    //      if (filter.getInitialConfig().filterFn) {
    //          Ext.raise('Unable to use a filtering function in conjunction with remote filtering.');
    //      }
    // });
    me.currentPage = 1;
    if (!suppressNext) {
      me.load();
    }
  } else if (!suppressNext) {
    me.fireEvent('datachanged', me);
    me.fireEvent('refresh', me);
  }
  if (me.trackStateChanges) {
    // We just mutated the filter collection so let's save stateful filters from this point forward.
    me.saveStatefulFilters = true;
  }
  // This is not affected by suppressEvent.
  me.fireEvent('filterchange', me, me.getFilters().getRange());
}

这是 fiddle https://fiddle.sencha.com/#fiddle/2ub7

中的实例