Как применить функцию фильтра к сетке подкачки с локальным (памятью) хранилищем в ExtJS6?

У меня есть пейджинговая сетка с локальным хранилищем, и я хочу применить фильтр, используя свою собственную функцию. Но это не удалось.

Из интернет-рекомендаций, которые я использовал remoteFilter: true а также enablePaging: true варианты в магазине конфиг.

И это прекрасно работает, если я фильтрую хранилище с конкретным объектом конфигурации:

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

к сожалению, этого недостаточно для построения сложных критериев фильтрации.

В соответствии с документацией filterBy метод в объекте store для использования функции в качестве фильтра. Но когда я предоставляю это так:

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

Я получил ошибку Uncaught Error: Unable to use a filtering function in conjunction with remote filtering.

Вот мой рабочий пример в скрипке https://fiddle.sencha.com/

Это конфигурация моего магазина и вся бизнес-логика от контроллера. Я пропущу просмотр конфигурации здесь, чтобы сосредоточиться на основной части ( 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)

Заранее спасибо, А.

2 ответа

Решение

Я наконец решил эту проблему!

Упомянутая ошибка возникла в методе хранения 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: true а также enablePaging: 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());
}

Вот живой пример в скрипке https://fiddle.sencha.com/

Вы не можете использовать оба remoteFilter а также filterBy в одном магазине. Решите, где должна быть логика фильтра - вкл Client Side или же Server Side?

Если на server side, установить remoteFilter как true и использовать filter действие с дополнительными параметрами, которые вы можете поймать на сервере и выполнить фильтр.

Если на client side, установить remoteFilter как false и использовать filterBy Функция, как вы прилагается.

Проверьте пример на скрипке (я только что изменил несколько вещей): https://fiddle.sencha.com/#fiddle/2ua4&view/editor

Другие вопросы по тегам