Autocomplete combobox filter for Ext JS 4 Grid (CRUD functionality)

Autocomplete combobox filter for Ext JS 4 Grid (CRUD functionality)

Hi, in this article I will show you how you can create filter input with autocomplete functionality for your Ext JS 4 grids. In this example I will use grid list with users and I will filter them by login. In the backend I have Zend Framework and Doctrine with CRUD functionality. But you can use what you want: node.js etc because the way how to do that is identical.

My grid look like the following picture:

34-extjs4

1. Combo box

35-extjs4

In your docked items in the initComponent Grid function please add field container with customised combo box:

this.dockedItems = [
            {
                xtype: 'toolbar',
                dock: 'top',
                items: [
                    {
                        xtype: 'button',
                        itemId: 'usersAdd',
                        text: 'Add user'
                    },
                    {
                        xtype: 'container',
                        flex: 1
                    },
                    {
                        xtype: 'fieldcontainer',
                        layout: 'hbox',
                        items:[
                            {
                                xtype: 'combobox',
                                anchor: '100%',
                                fieldLabel: '',
                                hideTrigger: true,
                                displayField: 'login',
                                minChars: 1,
                                queryDelay: 250,
                                store: Ext.create('DevJS.store.Users', {storeId: 'usersFilter'}),
                                queryParam: 'value',
                                typeAheadDelay: 200,
                                itemId: 'filter',
                                valueField: 'login'
                            },
                            {
                                xtype: 'button',
                                iconCls: 'button-search',
                                itemId: 'doFilter',
                                text: ''
                            }
                        ]
                    }
                ]
            },
            {
                xtype: 'pagingtoolbar',
                dock: 'bottom',
                width: 360,
                displayInfo: true,
                store: 'Users'
            }
        ];

2. Store

You have to create another instance of your users store with different store Id because your filter will work on the same store which is in the grid view:

36-extjs4

As you can see your filter have impact on two places (the combo box field and the grid view). Some of your users maybe will like this way but it’s not good idea.

Store code look like the following lines:

Ext.define('DevJS.store.Users', {
    extend: 'Ext.data.Store',
    model: 'DevJS.model.User',
    autoLoad: true,
    autoSync: true,
    remoteFilter: true,

    proxy: {
        type: 'direct',
        api: {
            read : 'Core.User.read',
            create : 'Core.User.create',
            update : 'Core.User.update',
            destroy : 'Core.User.destroy'
        },
        reader: {
            type: 'json',
            root: 'User'
        }
    }
});

The remoteFilter variable is responsible for filter actions, you can also filter your store locally if you set this value as false.

How it works?

a) standard way of store load – it’s sending simple request without value variable inside, so your Read method should send all records

39-extjs4

b) combox filter load – the combobox way is more advanced, combox has query param which will send combobox variable to server every time when user fire the change event and if the number of chars will be > minChars (in my case it’s 1) from config. And set in the filter object property name, in this case it’s ‘login’

38-extjs4

c) store filter load – it’s more complex but here you can use more than one property in filter object, but in this example we need only one ‘login’

40-extjs4

You have to adjust your read methods to this functionality. I use Zend Framework and Doctrine, so I wrote for all my Read methods special function to filter values.

public function read($params)
    {
        $qb = $this->em->createQueryBuilder();
        $qb->select('u')
            ->from('Core\Entity\User', 'u');

        $query = $this->filter($params, $qb, 'u')->getQuery();

        $results = $query->getArrayResult();

        return array('success'=>true, 'User' => $results);
    }

The example of json result:

37-extjs4

3. Events

Please go to controller, in my case it’s a Users Controller.

a) action listener in the init(this.control({})) function

'usersList > toolbar > fieldcontainer > button[itemId=doFilter]': {
                click: me.onUsersFilterClick
            }

b) filter function

onUsersFilterClick: function(button, e, eOpts) {
        var me = this, field = me.getUsersList().down('toolbar > fieldcontainer > combobox[itemId=filter]');

        me.getUsersList().getStore().clearFilter(true);
        me.getUsersList().getStore().filter('login', field.getValue());
    }

The clearFilter function clear filter object and true value as argument prevent sending request to server, because the filter method will do it with new values.

//without clear filter function, your store will add new value to existing ones in filter object

Bonus!

The return/enter functionality. Use case: user fill the textfield and use enter key to filter the users Grid:

a) next action listener

'usersList > toolbar > fieldcontainer > combobox[itemId=filter]': {
                select: {
                    fn: me.onUsersFilterSelect,
                    scope: me
                }
            },

b) select function

onUsersFilterSelect: function(combo, records, eOpts) {
        combo.nextSibling().fireEvent('click');
    }

And that’s it. Your user can use enter key or even mouse click now. Because we add listener to select event.

4. The final result

The Grid with new functionality look like the following picture:

41-extjs4

Have fun and see you soon.

Comments:
existdissolve
Reply
02/10/2013 at 11:49 AM

Nice article!

Don’t forget you can shorten the selector syntax for itemId by using the pound symbol, instead of the explicit property name: combobox[itemId=filter] becomes combobox#filter

Also, you might consider expanding your controller to use the new listen() method instead of just control(). With listen(), you can leverage the 3 new event domains (global, store, controller) in addition to the existing component domain. http://docs.sencha.com/extjs/4.2.1/#!/api/Ext.app.Controller-method-listen

Łukasz Sudoł To reply on comment
Reply
02/10/2013 at 2:26 PM

Thanks for the reply and your tips!

I read your blog and you have interesting articles too. I didn’t know about the new listen() method, I will read the Sencha docs to get more information about that.

Leave a Reply

Please fill all required fields


Drag circle to the rectangle on the right!

Send