I have a paging grid with local store, and I want to apply a filter using my own function. But it is failed.
From internet recommendations I used remoteFilter: true
and enablePaging: true
options in store config.
And it works perfectly if I filter store with specific configuration object:
store.filter([{ property: 'age', value: 12 }]);
unfortunately it is not enough to build complex filter criteria.
In accordance with documentation there is a special filterBy
method in store object to use function as filter. But, when I am providing it like this:
store.filterBy( function( record ) {
return record.get( 'age' ) <= 12;
});
I got an error Uncaught Error: Unable to use a filtering function in conjunction with remote filtering.
Here is my working example in fiddle https://fiddle.sencha.com/#fiddle/2u8l
This is my store configuration and all business logic from controller. I'll skip view configuration here to focus on main part( IMO )of code
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"
}]
}
}
});
In general I want to have ability to set up filter criteria on paging grid with local store programmatically. Function allows me to extend filter capabilities and build flexible logical expression using conjunction and disquisition. For example:
name.lenght <= 4 && ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0)
Thank you in advance, A.
I have finally resolved this issue!
Mentioned error raised in onFilterEndUpdate method of store in next lines:
...
me.getFilters().each(function(filter) {
if (filter.getInitialConfig().filterFn) {
Ext.raise('Unable to use a filtering function in conjunction with remote filtering.');
}
});
...
I have override this method in my store entity and commented out these lines. I know it is not best solution, but I could not find better one.
Here is the complete solution concerning this topic:
remoteFilter: true
and enablePaging: true
options:{
model: 'Ext.data.Model',
pageSize: 2,
remoteFilter: true,
proxy: {
type: 'memory',
enablePaging: true,
reader: {
type: 'json'
}
}
}
Proxy
instead of loadData
method:store.getProxy().data = this.getSimpsonsData().items;
store.reload();
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());
}
Here is live example in fiddle https://fiddle.sencha.com/#fiddle/2ub7