Search code examples
javascriptextjssencha-touchsencha-touch-2store

Sencha Touch store filterBy function


Hi I am trying to work with the store filterBy function but i am unable to make it work as I want. I have four buttons(A B C D) and a list with all data related to buttons When I click on the button I should filter accordingly Note:- when I click A ,I should get records of A when I click B , I should get records of B appended to A's list of records So actually when I click on the buttons I should have a array of button ids and filter the the list using these id's.

  filterList:function (list, index, target, record){
    var categories=[];
    categories.push(record.get('id'));
                                for(c=0;c<categories.length;c++)
                                {
                                Ext.getStore('mystore').filterBy(function(record){
                                  var id = record.get('id');
                                       if(id==categories[c])
                                        {       
                                            return true; 
                                        }

                                });
                                }

    }

Any help is appreciated.


Solution

  • What is wrong with your code

    The filterBy return function should always return a boolean value. You are only returning true, and no false. Besides that you are filtering the store in a loop, and the parameter record exists twice (as a parameter in the function filterList and in the return function of the filterBy).

    Example

    I created a Fiddle to show you where I came up with. I know it is ExtJs instead of Sencha Touch, but you will get the idea. I will step through the MainController, where all the logic is.

    I didn't clean the code so there is some duplication, but it's just a concept.

    Setting up some logic

    First I create a set of buttons on my view. See that I'm setting an action property.

    ...
    tbar: [{
        text: 'Filter a',
        action: 'a'
    }, {
        text: 'Filter b',
        action: 'b'
    }],
    ...
    

    Then I bind an onClick event to the button. In this event I use the action property as a searchValue, but it could be anything of course.

    ...
    onClick: function(button, event, eOpts) {
        var me = this,
            grid = me.getMainGrid(),
            store = grid.getStore(),
            filters = store.getFilters(),
            searchValue = button.action,
            regex = RegExp(searchValue, 'i'),
            filter = new Ext.util.Filter({
                id: button.id,
                filterFn: function(record) {
                    var match = false;
                    Ext.Object.each(record.data, function(property, value) {
                        match = match || regex.test(String(value));
                    });
                    return match;
                }
            });
    
        if (filters.containsKey(button.id)) {
            store.removeFilter(filter);
        } else {
            store.addFilter(filter);
        }
    },
    ...
    

    The magic

    The magic is in the filter instance. By adding new filter instances each time you filter, you can filter with several filters. If you push button a and button b they will respect each other. In that filter I use a regex to search through all data of the current model. I config an id to recognize the filter so I can remove it afterwards.

    filter = new Ext.util.Filter({
        id: button.id,
        filterFn: function(record) {
            var match = false;
            Ext.Object.each(record.data, function(property, value) {
                match = match || regex.test(String(value));
            });
            return match;
        }
    });
    

    If the filter doesn't exists it will be added, otherwise it will be removed.

    if (filters.containsKey(button.id)) {
        store.removeFilter(filter);
    } else {
        store.addFilter(filter);
    }
    

    Reset filters

    I also created a textfield to search through all data. Instead of adding and removing filters I just call clearFilter and add a new filter with new searchvalue.

    onKeyUp: function(textField, event, eOpts) {
        this.filterStore(textField.getValue());
    },
    
    filterStore: function(searchValue) {
        var me = this,
            grid = me.getMainGrid(),
            store = grid.getStore(),
            regex = RegExp(searchValue, 'i');
    
        store.clearFilter(true);
    
        store.filter(new Ext.util.Filter({
            filterFn: function(record) {
                var match = false;
                Ext.Object.each(record.data, function(property, value) {
                    match = match || regex.test(String(value));
                });
                return match;
            }
        }));
    }
    

    The complete maincontroller

    Ext.define('Filtering.controller.MainController', {
        extend: 'Ext.app.Controller',
    
        config: {
            refs: {
                mainGrid: 'maingrid'
            }
        },
    
        init: function() {
            var me = this;
    
            me.listen({
                global: {},
                controller: {},
                component: {
                    'segmentedbutton': {
                        toggle: 'onToggle'
                    },
                    'toolbar > button': {
                        click: 'onClick'
                    },
                    'textfield': {
                        keyup: 'onKeyUp'
                    }
                },
                store: {
                    '*': {
                        metachange: 'onMetaChange',
                        filterchange: 'onFilterChange'
                    }
                },
                direct: {}
            });
        },
    
        onLaunch: function() {
            var store = Ext.StoreManager.lookup('Users') || Ext.getStore('Users');
    
            store.load();
        },
    
        onMetaChange: function(store, metaData) {
            var grid = this.getMainGrid(),
                model = store.getModel(),
                // metadata
                fields = metaData.fields,
                columns = metaData.columns,
                gridTitle = metaData.gridTitle;
    
            model.fields = fields;
            grid.setTitle(gridTitle);
            grid.reconfigure(store, columns);
        },
    
        onFilterChange: function(store, filters, eOpts) {
            var me = this,
                grid = me.getMainGrid();
    
            grid.getSelectionModel().select(0);
        },
    
        /**
         * Used for the segmented buttons
         */
        onToggle: function(container, button, pressed) {
            var me = this,
                grid = me.getMainGrid(),
                store = grid.getStore(),
                //filters = store.getFilters(),
                searchValue = button.action,
                regex = RegExp(searchValue, 'i'),
                filter = new Ext.util.Filter({
                    id: button.id,
                    filterFn: function(record) {
                        var match = false;
                        Ext.Object.each(record.data, function(property, value) {
                            match = match || regex.test(String(value));
                        });
                        return match;
                    }
                });
    
            if (pressed) {
                store.addFilter(filter);
            } else {
                store.removeFilter(filter);
            }
        },
    
        /**
         * Used for the toolbar buttons
         */
        onClick: function(button, event, eOpts) {
            var me = this,
                grid = me.getMainGrid(),
                store = grid.getStore(),
                filters = store.getFilters(),
                searchValue = button.action,
                regex = RegExp(searchValue, 'i'),
                filter = new Ext.util.Filter({
                    id: button.id,
                    filterFn: function(record) {
                        var match = false;
                        Ext.Object.each(record.data, function(property, value) {
                            match = match || regex.test(String(value));
                        });
                        return match;
                    }
                });
    
            if (filters.containsKey(button.id)) {
                store.removeFilter(filter);
            } else {
                store.addFilter(filter);
            }
        },
    
        /**
         * Used for the textfield
         */
        onKeyUp: function(textField, event, eOpts) {
            this.filterStore(textField.getValue());
        },
    
        filterStore: function(searchValue) {
            var me = this,
                grid = me.getMainGrid(),
                store = grid.getStore(),
                regex = RegExp(searchValue, 'i');
    
            store.clearFilter(true);
    
            store.filter(new Ext.util.Filter({
                filterFn: function(record) {
                    var match = false;
                    Ext.Object.each(record.data, function(property, value) {
                        match = match || regex.test(String(value));
                    });
                    return match;
                }
            }));
        }
    });
    

    The complete view

    Ext.define('Filtering.view.MainGrid', {
        extend: 'Ext.grid.Panel',
        xtype: 'maingrid',
    
        tbar: [{
            xtype: 'segmentedbutton',
            allowMultiple: true,
            items: [{
                text: 'Filter a',
                action: 'a'
            }, {
                text: 'Filter b',
                action: 'b'
            }]
        }, {
            text: 'Filter a',
            action: 'a'
        }, {
            text: 'Filter b',
            action: 'b'
        }, {
            xtype: 'textfield',
            emptyText: 'Search',
            enableKeyEvents: true
        }],
        //title: 'Users', // Title is set through the metadata
        //store: 'Users', // we reconfigure the store in the metachange event of the store
        columns: [] // columns are set through the metadata of the store (but we must set an empty array to avoid problems)
    });