goog.ui.TabPane: Create tabs with Google Closure

Hi everyone,
by starting with this post I would like to begin a series of posts dedicated to the new javascript library released by Google: Closure!
Today I will focus my attention on tabs creation, since this is maybe the most common user interface component in a web application.
In order to create Closure tabs, we need to import the base js file (/goog/base.js) and then require the class goog.ui.TabPane. Inside our head (or body) we will get the following:




The code above, will do the following: 1. import the base library into the page, 2. dynamically load a series of additional js files which will be used to create and handle tabs components and events. Theoretically we could write more goog.require() statements, but they will be unnecessary because goog.ui.TabPane.TabPage, is able to require all files it needs, that is all the classes it uses internally (such goog.events, goog.dom and so on).
Ok, now that we have all the necessary files, let’s see how to do. There are fundamentally three ways to create ui components with Closure, one is totally code based, we can create components by writing all things in javascript, we can instead create a semantic HTML structure and then “convert” it to a ui component and finally we can mix things and create both components from HTML elements than from the scratch via javascript (in my example I will show this). To use an existent markup as the base for tabs component, we need a container (typically a div) containing a series of subelement (div works better here too) which contain respectively 2 or more subelements among which the first will represents the tab label and the others tab’s content. In practice the logic structure will be something like:


[tabs-container]
[tab-container]
[tab-label] TAB ONE [/tab-label]
[tab-content] CONTENT ONE [/tab-content]
[/tab-container]
[tab-container]
[tab-label] TAB TWO [/tab-label]
[tab-content] CONTENT TWO [/tab-content]
[/tab-container]
[tab-container]
[tab-label] TAB THREE [/tab-label]
[tab-content] CONTENT THREE [/tab-content]
[/tab-container]
[/tabs-container]

…and the HTML will be:

tab 1

tab 1 content

tab 2

tab 2 content

tab 3

tab 3 content

As you can see, the type of the tag doesn’t matter, what matters is the logic structure created.
Now, is possible to create a TabPane components by writing a single line of javascript:


new goog.ui.TabPane(goog.dom.$("tabs"));

With the code above we create a new instance of a TabPane component, which will be rendered using the “rules” of the given dom element (goog.dom.$() is the same as document.getElementById())
Is really so simple? Yes, but honestly is not so useful to haven’t a reference to the component, because we can’t handle events nor add extra elements, moreover our tabs will be display as an ugly pointed list rather than a cool tabs series. In fact Closure doesn’t apply a style to the ui components, but it simply handle the toggle of tabs by setting the containers with display “none” where necessary and making tabs dispatching certain events. Hey… this sucks! Wait! Closure, adds a series of CSS classes to the HTML nodes and the library provides several CSS (disseminated among the thousands of files) to give components a style (although the default theme is pretty ugly and you will feel the need to write your own stylesheet).
Ok, let’s see some concrete features and some more code, in order to: add a new tab and its relative content, get specific tab, enable/disable a tab, listen to tab selection/change.
First of all, let’s take a reference to the TabPane object:


var tabsPanel = new goog.ui.TabPane(goog.dom.$("tabs"));

Then, we can use its methods and we are able to select an arbitrary tab (the default behavior is to show the first)… let’s select the second:


tabsPanel.setSelectedPage(tabsPanel.getPage(1));

Closure consider a page (an object of type ui.TabPane.TabPage) the content related to a tab. The method setSelectedPage() takes as first argument an object of that type and we pass it by using getPage(), which instead returns the TabPage for a given index.
To add a new page (aka a new tab and its related content) we will use the method addPage in the following way:


// create a new dom element
var newPageContainer = goog.dom.$dom("div");

// add some text
newPageContainer.innerHTML = "I'm a new page!";

// put the page into TabPane
tabsPanel.addPage(new goog.ui.TabPane.TabPage(newPageContainer, "new tab"));

The code is pretty clear, goog.ui.TabPane.TabPage takes a dom node and a label as the first arguments.
Ok, let’s say we would like to disable the previous added page… it’s easy:


tabsPanel.getPage(3).setEnabled(false);

We can use its index to retrieve it and then call setEnabled()… of course if we create a reference to the page we can avoid getPage() method and enable the tab directly.
Let’s play a little with event handling, in order to toggle the status of a page (enabled/disabled). We can add a new HTML node:


toggle last tab!

and then:


goog.events.listen(goog.dom.$("toggle-btn"), "click", function() {

// get a reference to the page
var p = tabsPanel.getPage(3);

// toggle its state (set the opposite of its state ...enabled? -> disabled! ... disabled? -> enabled!)
p.setEnabled(!p.isEnabled());

// print a message to the console (this will throw an error if not available)
console.log("last tab is now: ", p.isEnabled() ? "enabled" : "disabled");

});

goog.events.listen takes three fundamental arguments: the dom node to observe, the event name and a callback function.

…and this is the end! (at the moment)… if you like this post, add my blog to your bookmarks, because I just begin to dig and write about Google Closure! ;^)

  • Hey, thanks for writing this! The Tabbing examples that Google supplies are a little odd so I appreciate you taking your time to refine the example.

  • Thanks a lot for the feedback, I’m going to write more about Closure soon, stay tuned ;)

    ps: I’m writing a library for webkit SQLite capabilities, based on Closure Tools ^_^