Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Add a custom button in column header dropdown menus {EXTJS 4}

Tags:

extjs4

I want a button in column header dropdown menu of grid in extjs4. so that i can add or delete columns which are linked in database. The button in red area is the one i'm looking for...

Any help will be appreciated... Thankyou..:)

like image 621
Narayan Singh Avatar asked Apr 27 '12 09:04

Narayan Singh


4 Answers

Couple of months ago I had the same problem. I've managed to solve it by extending Ext.grid.header.Container (I've overrided getMenuItems method). However, recently, I've found another solution which requires less coding: just add menu item manualy after grid widget is created.

I'll post the second solution here:

Ext.create('Ext.grid.Panel', {
    // ...
    listeners: {
        afterrender: function() {
            var menu = this.headerCt.getMenu();
            menu.add([{
                text: 'Custom Item',
                handler: function() {
                    var columnDataIndex = menu.activeHeader.dataIndex;
                    alert('custom item for column "'+columnDataIndex+'" was pressed');
                }
            }]);           
        }
    }
});

Here is demo.​

UPDATE

Here is demo for ExtJs4.1.

like image 116
Molecular Man Avatar answered Nov 06 '22 02:11

Molecular Man


From what I have been seeing, you should avoid the afterrender event.

Context:

The application I am building uses a store with a dynamic model. I want my grid to have a customizable model that is fetched from the server (So I can have customizable columns for my customizable grid).

Since the header wasn't available to be modified (since the store gets reloaded and destroys the existing menu that I modified - using the example above). An alternate solution that has the same effect can be executed as such:

Ext.create('Ext.grid.Panel', {
    // ...

    initComponent: function () {
        // renders the header and header menu
        this.callParent(arguments);

        // now you have access to the header - set an event on the header itself
        this.headerCt.on('menucreate', function (cmp, menu, eOpts) {
            this.createHeaderMenu(menu);
        }, this);
    },

    createHeaderMenu: function (menu) {
        menu.removeAll();

        menu.add([
            // { custom item here }
            // { custom item here }
            // { custom item here }
            // { custom item here }
        ]);
    }
});
like image 42
chemoish Avatar answered Nov 06 '22 03:11

chemoish


For people who would like to have not just one "standard" column menu but have an individual columnwise like me, may use the following

initComponent: function ()
{
    // renders the header and header menu
    this.callParent(arguments);

    // now you have access to the header - set an event on the header itself
    this.headerCt.on('menucreate', function (cmp, menu, eOpts) {
        menu.on('beforeshow', this.showHeaderMenu);
    }, this);
},

showHeaderMenu: function (menu, eOpts)
{
    //define array to store added compoents in
    if(this.myAddedComponents === undefined)
    {
        this.myAddedComponents = new Array();
    }

    var columnDataIndex = menu.activeHeader.dataIndex,
        customMenuComponents = this.myAddedComponents.length;

    //remove components if any added
    if(customMenuComponents > 0)
    {
        for(var i = 0; i < customMenuComponents; i++)
        {
            menu.remove(this.myAddedComponents[i][0].getItemId());
        }

        this.myAddedComponents.splice(0, customMenuComponents);
    }

    //add components by column index
    switch(columnDataIndex)
    {
        case 'xyz': this.myAddedComponents.push(menu.add([{
                            text: 'Custom Item'}]));

                break;
    }
}
like image 21
nobbler Avatar answered Nov 06 '22 01:11

nobbler


I took @nobbler's answer an created a plugin for this:

Ext.define('Ext.grid.CustomGridColumnMenu', {
    extend: 'Ext.AbstractPlugin',
    init: function (component) {
        var me = this;

        me.customMenuItemsCache = [];

        component.headerCt.on('menucreate', function (cmp, menu) {
            menu.on('beforeshow', me.showHeaderMenu, me);
        }, me);
    },

    showHeaderMenu: function (menu) {
        var me = this;

        me.removeCustomMenuItems(menu);
        me.addCustomMenuitems(menu);
    },

    removeCustomMenuItems: function (menu) {
        var me = this,
            menuItem;

        while (menuItem = me.customMenuItemsCache.pop()) {
            menu.remove(menuItem.getItemId(), false);
        }
    },

    addCustomMenuitems: function (menu) {
        var me = this,
            renderedItems;

        var menuItems = menu.activeHeader.customMenu || [];

        if (menuItems.length > 0) {
            if (menu.activeHeader.renderedCustomMenuItems === undefined) {
                renderedItems = menu.add(menuItems);
                menu.activeHeader.renderedCustomMenuItems = renderedItems;
            } else {
                renderedItems = menu.activeHeader.renderedCustomMenuItems;
                menu.add(renderedItems);
            }
            Ext.each(renderedItems, function (renderedMenuItem) {
                me.customMenuItemsCache.push(renderedMenuItem);
            });
        }
    }
});

This is the way you use it (customMenu in the column config let you define your menu):

Ext.define('MyGrid', {
    extend: 'Ext.grid.Panel',
    plugins: ['Ext.grid.CustomGridColumnMenu'],
    columns: [
        {
            dataIndex: 'name',
            customMenu: [
                {
                    text: 'My menu item',
                    menu: [
                        {
                            text: 'My submenu item'
                        }
                    ]
                }
            ]
        }
    ]
});

The way this plugin works also solves an issue, that the other implementations ran into. Since the custom menu items are created only once for each column (caching of the already rendered version) it will not forget if it was checked before or not.

like image 31
scho Avatar answered Nov 06 '22 02:11

scho