Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ExtJs - Filter a grid with a search field in the column header

In ExtJs, there are many options to filter a grid. There are two nice examples in the documentation, like referenced in this question.

  1. Remote filtering
  2. Local filtering

However, having the filter hidden in the default dropdown menu of Ext.ux.grid.FiltersFeature looks really awkward for me. A good ergonomic choice would to create search fields in the column headers, like @Ctacus shows in his question.

How can this be achieved ?

like image 420
Lorenz Meyer Avatar asked Feb 25 '14 12:02

Lorenz Meyer


1 Answers

After quite much research through the sparse documentation, and thanks to great questions and answers in SO, I came up with a simple class, that adds this functionality and and allows for configurations.

It looks like this:

Search filter fields in column header

You add this field in your grid like this:

Ext.define('Sandbox.view.OwnersGrid', {
    extend: 'Ext.grid.Panel',
    requires: ['Sandbox.view.SearchTrigger'],
    alias: 'widget.ownersGrid',
    store: 'Owners',
    columns: [{
        dataIndex: 'id',
        width: 50,
        text: 'ID'
    }, {
        dataIndex: 'name',
        text: 'Name',
    items:[{
        xtype: 'searchtrigger',
        autoSearch: true
    }]
},

The following configs are possible, and work like described in the doc for Ext.util.Filter:

  • anyMatch
  • caseSensitive
  • exactMatch
  • operator
  • additionnaly you can use autoSearch. If true, the filter searches as you type, if false or not set, one has to click on the search icon to apply the filter.

ExtJs 5 / 6 Source:

Ext.define('Sandbox.view.SearchTrigger', {
    extend: 'Ext.form.field.Text',
    alias: 'widget.searchtrigger',
    triggers:{
        search: {
            cls: 'x-form-search-trigger',
            handler: function() {
                this.setFilter(this.up().dataIndex, this.getValue())
            }
        },
        clear: {
            cls: 'x-form-clear-trigger',
            handler: function() {
                this.setValue('')
                if(!this.autoSearch) this.setFilter(this.up().dataIndex, '')
            }
        }
    },
    setFilter: function(filterId, value){
        var store = this.up('grid').getStore();
        if(value){
            store.removeFilter(filterId, false)
            var filter = {id: filterId, property: filterId, value: value};
            if(this.anyMatch) filter.anyMatch = this.anyMatch
            if(this.caseSensitive) filter.caseSensitive = this.caseSensitive
            if(this.exactMatch) filter.exactMatch = this.exactMatch
            if(this.operator) filter.operator = this.operator
            console.log(this.anyMatch, filter)
            store.addFilter(filter)
        } else {
            store.filters.removeAtKey(filterId)
            store.reload()
        }
    },
    listeners: {
        render: function(){
            var me = this;
            me.ownerCt.on('resize', function(){
                me.setWidth(this.getEl().getWidth())
            })
        },
        change: function() {
            if(this.autoSearch) this.setFilter(this.up().dataIndex, this.getValue())
        }
    }
})

For ExtJs 6.2.0, the following bug and its workaround is relevant to this, else the column cannot be flexed.

ExtJs 4 Source:

Ext.define('Sandbox.view.SearchTrigger', {
    extend: 'Ext.form.field.Trigger',
    alias: 'widget.searchtrigger',
    triggerCls: 'x-form-clear-trigger',
    trigger2Cls: 'x-form-search-trigger',
    onTriggerClick: function() {
        this.setValue('')
        this.setFilter(this.up().dataIndex, '')
    },
    onTrigger2Click: function() {
        this.setFilter(this.up().dataIndex, this.getValue())
    },
    setFilter: function(filterId, value){
        var store = this.up('grid').getStore();
        if(value){
            store.removeFilter(filterId, false)
            var filter = {id: filterId, property: filterId, value: value};
            if(this.anyMatch) filter.anyMatch = this.anyMatch
            if(this.caseSensitive) filter.caseSensitive = this.caseSensitive
            if(this.exactMatch) filter.exactMatch = this.exactMatch
            if(this.operator) filter.operator = this.operator
            console.log(this.anyMatch, filter)
            store.addFilter(filter)
        } else {
            store.filters.removeAtKey(filterId)
            store.reload()
        }
    },
    listeners: {
        render: function(){
            var me = this;
            me.ownerCt.on('resize', function(){
                me.setWidth(this.getEl().getWidth())
            })
        },
        change: function() {
            if(this.autoSearch) this.setFilter(this.up().dataIndex, this.getValue())
        }
    }
})
like image 192
Lorenz Meyer Avatar answered Sep 23 '22 23:09

Lorenz Meyer