EagleFox
EagleFox

Reputation: 1367

Filter store on combobox selection

I have tried this different ways, but still can't get the filter to work. My ext app lets user to choose a single state from a combobox, and the grid below displays more data on that selected "value"=state.. On select, the combobox fires a function that filters the store of the grid and updates the store... this is my store for the grid...

var store = Ext.create('Ext.data.Store', {
        autoLoad: true,
        id: 'OurData',
        pageSize: 20,
        pageNumber: 1,
        remoteSort: true,
        fields: [
    { name: 'States' },
    { name: 'FullName' },
    { name: 'Capital' },
    { name: 'Population' }
    ],
        proxy: {
            type: 'ajax',
            url: 'GetState/getS',
            reader: {
                type: 'json',
                root: 'myTable',
               idProperty: 'States',
                totalProperty: '@count'
            }
        }
    });
    store.loadPage(1);

this is my combobox

xtype: 'combo',
                    id: 'iccombo',
                    scope: this,
                    store: this.Combostore,
                    fieldLabel: 'Short State',
                    displayField: 'States',
                    valueField: 'States',
                    typeAhead: true,
                    triggerAction: 'all',
                    queryMode: 'remote',
                    name: 'State',
                    labelWidth: 125,
                    anchor: '95%',
                    listeners: {
                        scope: this,
                        select: this.fireFilter
                    }

and this is where the filter should take place...

fireFilter: function (value) {

    // Get passed value
    this.selectedC = value.getValue();
    console.log('selectedValue: ' + this.selectedC);

    // Clear existing filters
    this.store.clearFilter(false);

    // Build filter

    var myfilter = Ext.create('Ext.util.Filter', {
        scope: this,
        filterFn: function (item) {
            var fieldNames = item.fields.keys;

            for (var j = 0; j < fieldNames.length; j++) {
                var fieldName = fieldNames[j];
                if (item.data[fieldName] != null) {
                    var stringVal = item.data[fieldName].toString();
                    if (stringVal != null && stringVal.toLowerCase().indexOf(value.toLowerCase()) != -1) {
                        return true;
                    }
                }
            }
            return false;
        }

    });
    // Apply filter to store
    this.store.filter(myfilter);
}

when I run the code, it display all data in the grid, and on selection of combobox, it still shows the same data.. For some reason, the code never runs through the filterFn... because my console.log doesn't show up this is what I got in firebug's response

_dc     1352902173425
filter  [{"property":null,"value":null}]
limit   20
page    1
start   0

as you can clearly see, the selected 'value' is null, but my 'console.log' prints the value selected... I think the way I am getting the passed value and applying the filter is incorrect... can someone please take a look... thanks

UPDATE... I am able to get inside the function and my console.log shows all the fields... but once I get to the last if statement... I get this error

TypeError: value.toLowerCase is not a function

What am I doing wrong here? Thanks

Upvotes: 3

Views: 21962

Answers (2)

sra
sra

Reputation: 23973

In addition to dbrin's anwser I also can't understand why you are using remoteSort but not remoteFilter? You may also have a scope issue by using this.

Anyway I would recommend you to extend a new combo type so that you are also be able to clear your filter if you have the need to. Here is an extension I have written for my own use. Note that the filtering itself needs to be implemented in the onSearch method, which can be either a remote or a local sort.

Ext.define('Ext.ux.form.field.FilterCombo', {
    extend: 'Ext.form.field.ComboBox',
    alias: 'widget.filtercombo',
    /**
    * @cfg {string} recordField
    * @required
    * The fieldname of the record that contains the filtervalue
    */

    /**
    * @cfg {string} searchField
    * @required
    * The fieldname on which the filter should be applied
    */

    /**
    * @cfg {boolean} clearable
    * Indicates if the clear trigger should be hidden. Defaults to <tt>true</tt>.
    */
    clearable: true,

    initComponent: function () {
        var me = this;

        if (me.clearable)
            me.trigger2Cls = 'x-form-clear-trigger';
        else
            delete me.onTrigger2Click;

        me.addEvents(

            /**
            * @event clear
            *
            * @param {Ext.ux.form.field.FilterCombo} FilterCombo The filtercombo that triggered the event
            */
            'clear',
            /**
            * @event beforefilter
            *
            * @param {Ext.ux.form.field.FilterCombo} FilterCombo The filtercombo that triggered the event
            * @param {String/Number/Boolean/Float/Date} value The value to filter by
            * @param {string} field The field to filter on
            */
            'beforefilter'
        );

        me.callParent(arguments);
        // fetch the id the save way
        var ident = me.getId();

        me.on('select', function (me, rec) {
            var value = rec[0].data[me.recordField],
                field = me.searchField;
            me.fireEvent('beforefilter', me, value, field)
            me.onShowClearTrigger(true); 
            me.onSearch(value, field);
        }, me);
        me.on('afterrender', function () { me.onShowClearTrigger(); }, me);
    },

    /**
    * @abstract onSearch
    * running a search on the store that may be removed separately
    * @param {String/Number/Boolean/Float/Date} val The value to search for
    * @param {String} field The name of the Field to search on
    */
    onSearch: Ext.emptyFn,

    /**
    * @abstract onFilterRemove
    * removing filters from the the
    * @param {Boolean} silent Identifies if the filter should be removed without reloading the store
    */
    onClear: Ext.emptyFn,

    onShowClearTrigger: function (show) {
        var me = this;
        if (!me.clearable)
            return;
        show = (Ext.isBoolean(show)) ? show : false;
        if (show) {
            me.triggerEl.each(function (el, c, i) {
                if (i === 1) {
                    el.setWidth(el.originWidth, false);
                    el.setVisible(true);
                    me.active = true;
                }
            });
        } else {
            me.triggerEl.each(function (el, c, i) {
                if (i === 1) {
                    el.originWidth = el.getWidth();
                    el.setWidth(0, false);
                    el.setVisible(false);
                    me.active = false;
                }
            });
        }
        // Version specific methods
        if (Ext.lastRegisteredVersion.shortVersion > 407) {
            me.updateLayout();
        } else {
            me.updateEditState();
        }
    },

    /**
    * @override onTrigger2Click
    * eventhandler
    */
    onTrigger2Click: function (args) {
        this.clear();
    },

    /**
    * @private clear
    * clears the current search
    */
    clear: function () {
        var me = this;
        if (!me.clearable)
            return;
        me.onClear(false);
        me.clearValue();
        me.onShowClearTrigger(false);
        me.fireEvent('clear', me);
    }
});

Here is an untested implementation of your combo. Please note that I cleaned up your filterFn but I didn't make any further check.

{
    xtype: 'filtercombo',
    id: 'iccombo',
    scope: this,
    store: this.Combostore,
    fieldLabel: 'Short State',
    displayField: 'States',
    valueField: 'States',   
    typeAhead: true,
    triggerAction: 'all',
    queryMode: 'remote',
    name: 'State',
    labelWidth: 125,
    anchor: '95%',
    // begin new parts
    recordField: 'States',
    searchField: '',
    clearable: false,
    onSearch: function (me, value, field) {

        // New part!
        var store = Ext.StoreMgr.lookup('YourStoreIdName');

        // Clear existing filters
        store.clearFilter(false);

        // Build filter
        var myfilter = Ext.create('Ext.util.Filter', {
        scope: this,
        filterFn: function (item) {
            var fieldNames = item.fields.keys,
                fieldName, stringVal,
                len = fieldNames.length,
                j = 0;

            for (; j < len; j++) {
                fieldName = fieldNames[j];
                if (item.data[fieldName] != null) {
                    stringVal = item.data[fieldName].toString();
                    if (stringVal != null && stringVal.toLowerCase().indexOf(value.toLowerCase()) != -1) {
                        return true;
                    }
                }
            }
            return false;
        }
    });
        // Apply filter to store
        store.filter(myfilter);
    }
}

I guess this should work too

var myfilter = Ext.create('Ext.util.Filter', {
            scope: this,
            filterFn: function (rec) {
                var fieldValue = rec[this.fieldName];
                if (fieldValue && fieldValue === this.value)
                      return true;
            return false;
            }
        });

I set this before two vars to mark them as from a external scope.

Upvotes: 4

dbrin
dbrin

Reputation: 15673

i see 2 issues

  1. store should have remoteFilter: true set

  2. in JavaScript all variables declarations are picked out and hoisted to the beginning of the function. so any variables declared inside a loop should be taken out and declared at the top of the function. JS has no block scope (like Java).

Upvotes: 1

Related Questions