Search code examples
extjs4keyeventextjs-mvctabpanel

ExtJS 4 Arrow Navigation for Tab Panel


I'm trying to make the tabs in tabpanel navigable using arrow keys.

As tabpanel has no key events, my guess was to create a KeyMap or a KeyNav and attach it to the panel this way: This is part of the tabpanel def, it's inside another panel:

activeTab : 0,
xtype : 'tabpanel',
id : 'tabPanel',
alias : 'widget.mainpanels',    
listeners: {
    afterrender: function(tb) {
        this.bindDetailsPanelKeys(tb);
    },
    scope: this
}, [...]

And the function bindDetailsPanelKeys:

bindDetailsPanelKeys: function(tb) {
    console.log(tb); //Checking tb is the correct object.
    var tbMap = new Ext.util.KeyMap(tb, {           
    key: Ext.EventObject.RIGHT,
    fn: function(e) {
        console.log(e);
    // Code to calculate next tab and switch it.
    }
});

console.log(tb) output is as expected, it contains the tab panel object.

But all I receive after that is: Uncaught TypeError: Cannot call method 'on' of null from line var tbMap = new Ext.util.KeyMap(tb, {

I've checked the El property of tb and it's also correct and it has the on method on it's proto as well.

Any help will be very appreciated.

EDIT: I've found the solution. I'll post it in a moment.

Agustin.


Solution

  • Ok, this is how I managed to get around it.

    In first place I defined the tabpanel with its tabbar and as follows:

    [...]
    activeTab : 0,
    xtype : 'tabpanel',
    id : 'tabPanel',
    alias : 'widget.mainpanels',
    tabBar: {
        id: 'tabPanelTabBar',
        listeners: {
            afterrender: function(tb, eOpts) {
            this.bindDetailsPanelKeys(tb);
        },
        scope: this
    }},[...]
    

    For each tab item I added an attribute 'index' as I'didn't find another way to get the current tab numerical position. Here's an example:

    {
        xtype : 'categoryEdit',
        title : 'Detalles Categoría',                                   
        index: 1
    }
    

    And the binding function as follows. As Saket Patel suggested I'm giving the KeyMap constructor a reference to the 'el' element of the tab-bar (notice it's TabBar's 'el', not TabPanel's 'el').

    bindDetailsPanelKeys: function(tabBar) {
        var tbRightMap = new Ext.util.KeyMap(tabBar.getEl(), { //RIGHT ARROW
            key: Ext.EventObject.RIGHT,
            fn: function(e) {
                var totalItems = tabBar.items.length, //total tabs
                activeTabIndex = tabBar.tabPanel.getActiveTab().index, //current tab index
                nextTabIndex = (activeTabIndex % totalItems) + Math.ceil(activeTabIndex/totalItems) - 1; //Calculate next index    
                tabBar.tabPanel.setActiveTab(nextTabIndex);
            }
    });
    
    var tbLeftMap = new Ext.util.KeyMap(tabBar.getEl(), { //LEFT ARROW          
        key: Ext.EventObject.LEFT,
        fn: function(e) {
            var totalItems = tabBar.items.length,
            activeTabIndex = tabBar.tabPanel.getActiveTab().index;
            prevTabIndex = (activeTabIndex == 1) ? 3 : activeTabIndex - 2;
            tabBar.tabPanel.setActiveTab(prevTabIndex);
    }
    });
    

    I hope somebody finds it useful.