Question

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?

Was it helpful?

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>

OTHER TIPS

In Dojo 1.10, reverting to the previous tab is the normal behaviour for TabContainers (instead of reverting to the first tab).

Presumably, you could use dojo/aspect to get the old behaviour (warning: not tested):

require( [ 'dijit/registry', 'dojo/aspect', 'dojo/_base/lang' ],
    function( registry, aspect, lang )
    {
        var tabContainer = registry.byId( 'tab_container');
        aspect.before( tabContainer, 'removeChild', lang.hitch( tabContainer, function( page )
        {
            if(this.selectedChildWidget === page)
            {
                this.selectedChildWidget = undefined;
                if(this._started)
                {
                    var children = this.getChildren();
                    this.selectChild( children[0] );
                }
            }

            return page;
        } ) );
    }
);

Or, alternatively, you could use the onClose extension point on a tab's ContentPane:

require( [ 'dijit/registry', 'dojo/_base/lang' ],
    function( registry, lang ) {
        newTabPane.onClose = lang.hitch(this, function () {
            // select first
            var tabContainer = registry.byId('tab_container'),
                all_tabs = tabContainer.getChildren();
            tabContainer.selectChild( all_tabs[0] );

            // allow save to go ahead
            return true;
        });
    }
);

Obviously, both these approaches would allow you to select a specific different pane on a tab being closed instead with a little tweaking...

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top