javascriptuser-interfacedojodijit.layout

How to change dojo content tab focus when closing a tab to focus on previous tab instead of first tab?


I'm using Dojo's Dijit Layout for generating content tab-panes similar to Dijit Theme Tester Demo. All of the tabs here are closeable.

The issue is: when I close a tab it goes back to the first tab in the list instead of the previous tab (available next to it).

You can think of it like opening a new tab in Firefox or Chrome and try closing the last tab.... on closing tab, it changes the focus to the previous tab which is a predictable behavior for working with tabs. But with dijit.TabContainers, by default it goes back to the very first tab instead of previous one. This is a serious flaw when you consider the UI basics.

I have checked with dojo docs, but don't found any hint on this. Any idea how to it?


Solution

  • Ok so when the [X] button on the dijit.layout.ContentPane (tab) is clicked an event onClose is generated, the dijit.layout.TabContainer is listening to this event, so when this happens, it executes the callback closeChild() then the function removeChild() is executed, this last one is the one you should override.

    The tabContainer inherits this two functions from dijit.layout.StackContainer you should check the API documentation.

    So for being able to modify the default behavior of the closing tabs, you should override the default functionality, in the example below i do this. Read the comments for info on where to add your logic.

    E.g.

    <script>
        require([
            "dojo/parser",
    
            "dojo/_base/lang", //this is the one that has the extend function
            "dojo/topic", //this is needed inside the overrided function
    
            "dijit/layout/TabContainer",
            "dijit/layout/ContentPane", 
    
            "dojo/domReady!"
        ], function(Parser, lang, topic, tabContainer, contentPane){
            Parser.parse();
    
            // this will extend the tabContainer class and we will override the method in question
            lang.extend(tabContainer, {
    
                // this function, i copied it from the dijit.layout.StackContainer class
                removeChild: function(/*dijit._Widget*/ page){
    
                    // for this to work i had to add as first argument the string "startup"
                    this.inherited("startup", arguments);
    
                    if(this._started){
                        // also had to call the dojo.topic class in the require statement
                        topic.publish(this.id + "-removeChild", page);  
                    }
    
                    if(this._descendantsBeingDestroyed){ return; }
    
                    if(this.selectedChildWidget === page){
                        this.selectedChildWidget = undefined;
                        if(this._started){
                            var children = this.getChildren();
                            if(children.length){
    
                                // this is what you want to add your logic
                                // the var children (array) contains a list of all the tabs
                                // the index selects the tab starting from left to right 
                                // left most being the 0 index   
    
                                this.selectChild(children[0]);
                            }
                        }
                    }
    
                    if(this._started){
                        this.layout();
                    }
                }
            });
    
            // now you can use your modified tabContainer WALAAAAAAA!
            // from here on, normal programmatic tab creation
            var tc = new tabContainer({
                style: "height: 100%; width: 100%;",
            }, "tab-container-div-id");
    
            var cp1 = new contentPane({
                title: "First Tab",
                closable: true
            });
            tc.addChild(cp1);
    
            var cp2 = new contentPane({
                title: "Second Tab",
                closable: true
            });
            tc.addChild(cp2);
    
            var cp3 = new contentPane({
                title: "Third Tab",
                selected: true,
                closable: true
            });
            tc.addChild(cp3);
    
            tc.startup();
        });
    </script>