Menus, Toolbars, and Buttons in Ext JS 3.2

Exclusive offer: get 80% off this eBook here
Learning Ext JS 3.2

Learning Ext JS 3.2 — Save 80%

Build dynamic, desktop-style user interfaces for your data-driven web applications using Ext JS

₨831.00    ₨166.20
by Colin Ramsay Shea Frederick Steve 'Cutter' Blades | October 2010 | AJAX Open Source

In this article, by Shea Frederick, Colin Ramsay, Steve 'Cutter' Blades, & Nigel White, authors of Learning Ext JS 3.2, we will  learn how to use toolbars, which contain buttons that call a function on click, or that pop up a submenu on click, or cycle between several submenu options on each click.

The primary classes we will cover in this article are:

  • Ext.menu.Menu: A Container class which by default displays itself as a popup component, floating above all other document content. A menu's child items behave in a similar manner to buttons, and may call a handler function on mouse click. A menu may also be used as a static component within a page.
  • Ext.Toolbar: A Container class which arranges its child Components horizontally in the available width, and manages overflow by offering overflowed Components in a popup menu.
  • Ext.Button: The primary handler for button creation and interaction. A Component class which renders a focusable element which may be configured with a handler function which is called upon mouse click, or a menu to display upon mouse click.
  • Ext.SplitButton: A subclass of button which calls a handler function when its main body is clicked, but also renders an arrow glyph to its right which can display a dropdown menu when clicked.
  • Ext.CycleButton: A subclass of SplitButton which cycles between checking individual menu options of its configured menu on each click. This is similar to cycling through different folder views in Windows Explorer.
  • Ext.ButtonGroup: A Panel class which lays out child Components in a tabular format across a configurable number of columns.

 

Learning Ext JS 3.2

Learning Ext JS 3.2

Build dynamic, desktop-style user interfaces for your data-driven web applications using Ext JS

  • Learn to build consistent, attractive web interfaces with the framework components
  • Integrate your existing data and web services with Ext JS data support
  • Enhance your JavaScript skills by using Ext's DOM and AJAX helpers
  • Extend Ext JS through custom components
  • An interactive tutorial packed with loads of example code and illustrative screenshots
        Read more about this book      

(For more resources on Ext JS, see here.)

What's on the menu?

We will begin by introducing the Menu class which will be used in all following examples.

We are going to demonstrate usage of the Menu class as both a static component within a page, and as a popup. Both menus will be configured with the same options by using a technique where we define a variable called menuItems to reference an array which specifies the menu's items, and use it in both cases.

The Menu class inherits from Container, so any menu options are child Components specified in the items config. It also inherits the usual Component config options such as renderTo, and the width option.

The static menu will be rendered to the document body, and in order for it to be rendered as a visible, static element in the document, we configure it with floating: false.

So the configuration we end up with is as follows:

new Ext.menu.Menu({
renderTo: document.body,
width: 150,
floating: false,
items: menuItems
});

The popup menu needs no extra configuring aside from its items. We do need to decide when and where to display it. In this case we will add a contextmenu (right click) event listener to the document, and show the menu at the mouse event's position:

var contextMenu = new Ext.menu.Menu({
items: menuItems
});
Ext.getDoc().on({
contextmenu: function(eventObj) {
contextMenu.showAt(eventObj.getXY());
},
stopEvent: true
});

When we run this example, the static menu will be visible. When we right click on the document, the result should be the two menus shown below. Notice how only the second, popup menu has a shadow to indicate that it floats above the document.

The menu's items

The menuItems variable references an array which should be familiar by now. Just like the items config of a FormPanel, it's a list of child Components or config objects. In a menu, a config object with no xtype creates a MenuItem Component. The MenuItem class accepts the following config options in addition to those it inherits:

  • icon: The URL of an image to display as an icon
  • iconCls: A CSS class name which allows a stylesheet to specify a background image to use as an icon
  • text: The text to display
  • handler: A function to call when the item is clicked
  • menu: A Menu object, or Menu configuration object or an array of menu items to display as a submenu when the item is clicked

Because a menu inherits from Container, it can accept other Components as child items. If some complex, menu option dependent input is required, a menu may be configured with a panel as a child item. The menu config of "Menu Option 2" we're creating next contains a FormPanel as its sole child item:

{
text: 'Menu Option 2',
iconCls: 'flag-green',
menu: {
plain: true,
items: {
xtype: 'form',
border: false,
bodyStyle: 'background:transparent;padding:5px',
labelWidth: 70,
width: 300,
defaults: {
anchor: '100%'
},
items: [{
xtype: 'combo',
editable: false,
fieldLabel: 'Select',
triggerAction: 'all',
store: [ [0, 'One or...'], [1 ,'The other']],
value: 0,
getListParent: function() {
return this.el.up('div.x-menu');
}
}, {
xtype: 'textfield',
fieldLabel: 'Title'
}],
fbar: [{
text: 'Submit'
}]
}
}
}

The configurations in the above object will mostly be familiar by now.

There is one extra config we use for the menu which contains the FormPanel.

  • plain: Specify as true so that the menu does not have to show the incised line for separating icons from text

The panel within the menu has the following configs:

border: Specify as false to produce a panel with no borders.

bodyStyle: A CSS style string to apply to the document body. We want to make it transparent to allow the menu to show, and we apply padding.

The ComboBox must render its dropdown list to the menu's element so that clicking on the list does not trigger the menu to hide:

  • GetListParent: This is a function which a ComboBox may be configured with. It must return the HTML element to render the dropdown list into. By default a ComboBox renders its dropdown into the document. We call the up function of the Ext.Element class to find the ancestor node of the combo's element which is a DIV which has the CSS class "x-menu".

The FormPanel as a child of a menu will display like this:

A toolbar for every occasion

An Ext JS Panel, and every Ext JS Component which inherits from the Panel class (This includes Window, TreePanel, and GridPanel) can be configured to render and manage a toolbar docked above, or below the panel's body—or both if really necessary. These are referred to as the top and bottom toolbars, or tbar and bbar for short.

Panels and subclasses thereof may also be configured with a footer bar which renders buttons right at the bottom of the panel—below any bottom toolbar.

The Toolbar class is also an Ext JS Component in its own way, and may when necessary be used on its own, or as a child Component of any Container.

Our second example renders a toolbar standalone into the body of the document. We will use all the main button types to illustrate their usage before moving on to add handlers to react to user interaction. The toolbar will contain the following child components:

  • A basic button
  • A button configured with a menu which is displayed when the button is clicked
  • A SplitButton which will display a menu only when its arrow glyph is clicked
  • A CycleButton which on click, cycles between three different options
  • A pair of mutually exclusive toggle buttons of which only one may be in a "pressed" state at once

Ext.onReady(function(){
new Ext.Toolbar({
renderTo: Ext.getBody(),
items: [{
xtype: 'button',
text: 'Button'
},{
xtype: 'button',
text: 'Menu Button',
menu: [{
text: 'Better'
},{
text: 'Good'
},{
text: 'Best'
}]
},{
xtype: 'splitbutton',
text: 'Split Button',
menu: [{
text: 'Item One'
},{
text: 'Item Two'
},{
text: 'Item Three'
}]
}, {
xtype: 'cycle',
showText: true,
minWidth: 100,
prependText: 'Quality: ',
items: [{
text: 'High',
checked: true
}, {
text: 'Medium'
}, {
text: 'Low'
}]
}, {
text: 'Horizontal',
toggleGroup: 'orientation-selector'
}, {
text: 'Vertical',
toggleGroup: 'orientation-selector'
}]
});
});

As usual, everything is inside our onReady event handler. The items config holds our toolbar's entire child Components—I say child Components and not buttons because as we now know, the toolbar can accept many different types of Ext JS Components including entire forms or just form fields—which we will be implementing later on in this article.

The result of the above code looks like this:

The default xtype for each element in the items config is button. We can leave out the xtype config element if button is the type we want, but I like to include it just for clarity.

Button configuration

In addition to inherited config options, a button accepts the following configurations which we will be using in the following examples for this article:

  • icon: The URL of an image to display as an icon
  • iconCls: A CSS class name which allows a stylesheet to specify a background image to use as an icon
  • text: The text to display
  • handler: A function to call when the button is clicked
  • menu: A Menu object, or Menu configuration object, or an array of menu items to display as a submenu when the button is clicked
  • enableToggle: Specify as true to make a single button toggleable between pressed and unpressed state
  • toggleGroup: A mnemonic string identifying a group of buttons of which only one may be in a "pressed" state at one time
  • toggleHandler: A function to be called when a button's "pressed" state is changed

A basic button

Creating a button is fairly straightforward; the main config option is the text that is displayed on the button. We can also add an icon to be used alongside the text if we want to. A handler function is called when the button is clicked.

Here is the most basic configuration of a button:

{
xtype: 'button',
text: 'Button',
handler: functionReference
}

The following screenshot shows what happens when the mouse is hovered over the Button button:

Button with a menu

A button may be configured to act as a trigger for showing a dropdown menu. If configured with a menu option, clicking the button displays a menu below the button. The alignment of the menu is configurable, but defaults to being shown below the button.

Each option within the menu may itself be configured with a menu option allowing a familiar cascading menu system to be built very easily. The following is a config for a button which displays a dropdown menu upon click:

{
xtype: 'button',
text: 'Button',
menu: [{
text: 'Better'
},{
text: 'Good'
},{
text: 'Best'
}]
}

The following screenshot shows what happens when the Menu Button is clicked on, and the mouse is hovered over the Best option:

Learning Ext JS 3.2 Build dynamic, desktop-style user interfaces for your data-driven web applications using Ext JS
Published: October 2010
eBook Price: ₨831.00
Book Price: ₨1,386.00
See more
Select your format and quantity:
        Read more about this book      

(For more resources on Ext JS, see here.)

Split button

A split button may sound like a complex component, but it is no more complex to create than a plain button. By using a split button we get the ability to specify a click handler which is called when the main body of the button is clicked. But we can also configure in a menu which will be displayed when the arrow glyph to the right of the main body is clicked.

{
xtype: 'split',
text: 'Split Button',
menu: [{
text: 'Item One'
},{
text: 'Item Two'
},{
text: 'Item Three'
}]
}

The following screenshot shows what happens when the Split Button's arrow glyph is clicked:

Toggling button state

Sometimes it is useful to have a button which "sticks" in the pressed state to indicate switching some state within our app. To enable a single button to be clicked to toggle between the pressed and unpressed state, configure the button with enableToggle: true.

If a set of buttons are to toggleable, but only one may be pressed at once, configure each button in that set with a toggleGroup. This is an ID string which links buttons which enforce this rule.

Toggleable buttons may be configured with a toggleHandler function which is called whenever the button's state changes in either direction.

{
text: 'Horizontal',
toggleGroup: 'orientation-selector'
}, {
text: 'Vertical',
toggleGroup: 'orientation-selector'
}

This code produces the pair of buttons below in which only one orientation may be selected at once, Horizontal or Vertical:

Toolbar item alignment, dividers, and spacers

By default, every toolbar aligns elements to the leftmost side. There is no alignment config for a toolbar, so if we want to align all of the toolbar buttons to the rightmost side, we need to add a fill item to the toolbar. This item is sometimes referred to as a 'greedy spacer'. If we want to have items split up between both the left and right sides, we can also use a fill, but place it between items:

{
xtype: 'tbfill'
}

Pop this little guy in a toolbar wherever you want to add space and it will push items on either side of the fill to the ends of the tool bar, as shown below:

We also have elements that can add space or a visual vertical divider, like the one used between the Menu Button and the Split Button.

The spacer adds a few pixels of empty space that can be used to space out buttons, or move elements away from the edge of the toolbar:

{
xtype: 'tbspacer'
}

A divider can be added in the same way:

{
xtype: 'tbseparator'
}

Shortcuts

Ext JS has many shortcuts that can be used to make coding faster. Shortcuts are a character or two that can be used in place of a configuration object. For example, consider the standard toolbar filler configuration:

{
xtype: 'tbfill'
}

The shortcut for a toolbar filler is a hyphen and a greater than symbol:

'->'

Not all of these shortcuts are documented. So be adventurous, poke around the source code that is distributed in the src folder of the SDK download, and see what you can find. Here is a list of the commonly-used shortcuts:

Icon buttons

The standard button can be used as an icon button like the ones we see used in text editors to make text bold or italic—simply a button with an icon and no text. Two steps need to be taken to make an icon button—defining an image to be used as the icon and applying the appropriate class to the button.

{
xtype: 'tbbutton',
cls: 'x-btn-icon',
icon: 'images/bomb.png'
}

This could just as easily be an icon beside text by changing the style class and adding the text config.

{
xtype: 'tbbutton',
cls: 'x-btn-text-icon',
icon: 'images/bomb.png',
text: 'Tha Bomb'
}

Another method for creating an icon button is to apply a CSS class to it that contains a background image. With this method we can keep the references to images in our CSS instead of our JavaScript, which is preferable whenever possible.

{
xtype: 'tbbutton',
iconCls: 'bomb'
}

The CSS to go along with this would have a background image defined, and the CSS 'important' flag set.

.bomb {
background-image: url( images/bomb.png ) !important;
}

Button events and handlers—click me!

A button needs to do more than just look pretty—it needs to react to the user. This is where the button's handler and events come in. A handler is a function that is executed when a button is clicked.

The handler config is where we add our function, which can be an anonymous function like below or a method of a class—any function will do:

{
xtype: 'button',
text: 'Button',
handler: function(){
Ext.Msg.alert('Boo', 'Here I am');
}
}

This code will pop up an alert message when the button is clicked. Just about every handler or event in Ext JS passes a reference to the component that triggered the event as the first argument. This makes it easy to work with whichever component that fired this handler, calling the disable method on it.

{
xtype: 'tbbutton',
text: 'Button',
handler: function(f){
f.disable();
}
}

We can take this reference to the button—a reference to itself—and access all of the properties and functions of that button. For this sample, we have called the disable function which grays out the button and makes it non-functional.

We can have more fun than just disabling a button. Why don't we try something more useful?

Learning Ext JS 3.2 Build dynamic, desktop-style user interfaces for your data-driven web applications using Ext JS
Published: October 2010
eBook Price: ₨831.00
Book Price: ₨1,386.00
See more
Select your format and quantity:
        Read more about this book      

(For more resources on Ext JS, see here.)

Loading content on menu item click

Let's take our button click and do something more useful with it. For this example, we are going to add a config option named helpfile to each menu item that will be used to determine what content file to load in the body of our page:

{
xtype: 'tbsplit',
text: 'Help',
menu: [{
text: 'Genre',
helpfile: 'genre',
handler: Movies.showHelp
},{
text: 'Director',
helpfile: 'director',
handler: Movies.showHelp
},{
text: 'Title',
helpfile: 'title',
handler: Movies.showHelp
}]
}

Note the helpfile config option that we have added to each of the menu items configs. We have made this config property up so that we have a way to store a variable that is unique to each menu item. This is possible because config properties can be anything we need them to be, and are copied into the Component upon construction, and become properties of the Component. In this case, we are using a config property as a reference to the name of the file we want to load.

The other new thing we are doing is creating a collection of functions to handle the menu item click. These functions are all organized into a Movies object.

var Movies = function() {
var helpbody;
return {
showHelp : function(btn){
Movies.doLoad(btn.helpfile);
},
doLoad : function(file){
helpbody = helpbody ||
Ext.getBody().createChild({tag:'div'});
helpbody.load({
url: 'html/' + file + '.txt'
});
},
setQuality: function(q) {
helpbody = helpbody ||
Ext.getBody().createChild({tag:'div'});
helpbody.update(q);
}
};
}();

This piece of code is worth reading a few times until you understand it. It illustrates the creation of a singleton object.

Notice that the function has () after it. It is called immediately returning an object, instead of a class that could be instantiated.

The Movies variable is assigned to reference whatever that function returns. It does not reference the function.

The object returned from that function contains three functions. These are the "member functions" of the Movies singleton object. It offers utility methods which our example code will use.

All the functions have access to the helpbody variable because they were declared within the same function it was declared in. They can use that variable, but it is not available to outside code. This is an important capability of singleton objects built in this slightly confusing manner.

Form fields in a toolbar

As the Toolbar class inherits from Container, it can be used to house any Ext JS Component. Naturally, form fields and combo boxes are very useful items to have on a toolbar. These are added as child items just as with all Container classes we have encountered so far:

{
xtype: 'textfield'
}

In the same way as we created form fields, we add the form fields to the items array, which will place the form fields within the toolbar. Now let's make the form field do something useful, by having it perform the same functionality as our help menu, but in a more dynamic way.

{
xtype: 'textfield',
listeners: {
specialkey: Movies.doSearch
}
}

This listener is added directly to the form field's config. For this, we are using a specialkey listener. This is the listener that is used to capture edit keystrokes, such as Enter and Delete among others. The handler function will be added to our small Movies class created earlier:

doSearch : function(field, keyEvent){
if (keyEvent.getKey() == Ext.EventObject.ENTER) {
Movies.doLoad(field.getValue());
}
}

Now the text field in our toolbar that enables us to type in the name of the text file to load should look like the following. Try typing in some of the samples used in our menu, such as director or title:

Buttons don't have to be in a toolbar

Up until now, we have been dealing with buttons in toolbars. But because buttons are part of the Ext JS Components class hierarchy, they can be used as child items of any Container, not just toolbars. When used outside of a toolbar, they are themed in a slightly different way.

A button can be added to the items array, just like we would add a panel or other child components.

new Ext.Window({
title: 'Help',
id: 'helpwin',
width: 300,
height: 300,
items: [{
xtype: 'button',
text: 'Close',
handler: function(){
Ext.getCmp('helpwin').close();
}
}]
}).load("html/director.txt ").show();

The above code fragment would produce the following display:

Toolbars in panels

Toolbars can be configured into all Ext JS Panel classes (Panel, GridPanel, TreePanel, and Window) docked either above or below the panel, body (or both)

Panel classes, such as the window and the grid, have a top and bottom toolbar config, along with a buttons config:

  • tbar: A toolbar, or toolbar configuration object, or an array specifying toolbar child items. This causes a toolbar to be docked above the panel's body.
  • bbar: A toolbar, or toolbar configuration object, or an array specifying toolbar child items. This causes a toolbar to be docked below the panel's body.
  • fbar: Also may be specified as buttons. A toolbar, or toolbar configuration object, or an array specifying toolbar child items, which specifies a toolbar to be placed into the panel's footer element.

If we wanted to place a toolbar at the top of a window, we would specify a tbar config option which references an array of toolbar child config objects like this:

new Ext.Window({
title: 'Help',
width: 300,
height: 300,
renderTo: document.body,
closeAction: 'hide',
layout: 'fit',
tbar: [{
text: 'Close',
handler: function(){
winhelp.hide();
}
},{
text: 'Disable',
handler: function(t){
t.disable();
}
}]
});

When this window is activated by clicking the Director help menu entry, this produces the following display:

Of course if we wanted that same toolbar on the bottom of the window, we can change from a tbar to a bbar.

We can also specify a toolbar (or config of a toolbar, or toolbar's items) to be rendered into the footer area of a panel or window. Buttons are themed as normal buttons in a footer bar, and by default are aligned to the right:

new Ext.Window({
title: 'Help',
width: 300,
height: 300,
renderTo: document.body,
closeAction: 'hide',
layout: 'fit',
fbar: [{
text: 'Close',
handler: function(){
winhelp.hide();
}
}]
});

If the help window was configured in this way, it would display like this:

Ext JS also has a custom toolbar for paged grids which contains all of the buttons for moving through pages of results.

Toolbars unleashed

As mentioned above, the toolbar class is a special type of Container class which lays out its child components in a particular, preconfigured way. We can use it to house more complex Components, and we can experiment with using different layout types to size and arrange the child Components in different ways.

In the final example, we use the hbox (horizontal box) layout to arrange ButtonGroups across the toolbar, and force them to be vertically sized to the size of the highest one, to produce a pleasing, even ribbon effect.

new Ext.Panel({
title: 'Panel with heavyweight toolbar',
renderTo: document.body,
width: 600,
height: 400,
tbar: new Ext.Toolbar({
layout: {
type: 'hbox',
align: 'stretchmax'
},
items: [{
xtype: 'buttongroup',
title: 'Group 1',
columns: 1,
items: [{
text: 'Group 1 Button One',
handler: handlerFn
},{
text: 'Group 1 Button Two',
handler: handlerFn
},{
text: 'Group 1 Button Three',
handler: handlerFn
}]
},{

This example will produce output like this:

This example illustrates the concept that a toolbar is a Container which may contain any Component, and also that a ButtonGroup is a Container with the same heritage. The first three ButtonGroups contain Buttons; the last one for a slight change of style contains MenuItems.

Summary

In this article, we had the chance to play with a couple of different ways to create toolbar items, including using a config object or its shortcut. The many options available for toolbars make them a useful component for everything from the simplest button bar, to a complex combination of buttons, menus, and form fields. Interacting with the buttons, menus, and form fields is easy using the built-in handlers.


Further resources on this subject:


About the Author :


Colin Ramsay

Colin Ramsay began his web career hacking around ASP websites in a part-time developer job when he was at university. Since then he's been involved with a range of web technologies, which have provided a springboard for the formation of his UK-based web development company, run in tandem with his fledgling writing projects.

Shea Frederick

Shea Frederick began his career in web development before the term 'Web Application' was commonplace. By the late 1990s, he was developing web applications for Tower Records that combined the call center interface with inventory and fulfillment. Since then, Shea has worked as a developer for several companies—building and implementing various commerce solutions, content management systems, and lead tracking programs.

Integrating new technologies to make a better application has been a driving point for Shea's work. He strives to use open source libraries as they are often the launching pad for the most creative technological advances. After stumbling upon a young user interface library called YUI-ext several years ago, Shea contributed to its growth by writing documentation, tutorials, and example code. He has remained an active community member for the modern YUI-ext library—Ext JS. Shea's expertise is drawn from community forum participation, work with the core development team, and his own experience as the architect of several large, Ext JS-based web applications. He currently lives in Baltimore, Maryland with his wife and two dogs and spends time skiing, biking, and watching the Steelers.

Shea is the primary author of the first book published on Ext JS, a book which helps to ease beginners into the Ext JS library. He is also a core developer on the Ext JS project along with writing columns for JSMag and running the local Baltimore/DC JavaScript Meetup. His ramblings can be found on his blog, http://www.vinylfox.com and open source code contributions on Github at http://www.github.com/VinylFox/.

Steve 'Cutter' Blades

Cutter is the Senior Web Developer for Dealerskins, a Nashville, Tennessee based hosting provider that develops websites for the Automobile Dealership market. Cutter began his web career when he began learning HTML 1 while in the US Army and stationed with the National Security Agency. Cutter got into application development as a Corporate Support Specialist for a regional ISP, just prior to becoming the IT Director of Seacrets, a large resort destination on the Eastern Shore of Maryland. Cutter has extensive experience as a server- and client-side developer, with a popular blog dedicated to ColdFusion, Ext JS, and other web development technologies.

Books From Packt


jQuery Plugin Development Beginner's Guide
jQuery Plugin Development Beginner's Guide

Joomla! 1.5 JavaScript jQuery
Joomla! 1.5 JavaScript jQuery

JavaScript Testing Beginner's Guide
JavaScript Testing Beginner's Guide

CMS Design Using PHP and jQuery
CMS Design Using PHP and jQuery

Drupal 6 Panels Cookbook
Drupal 6 Panels Cookbook

Joomla! 1.5 Top Extensions Cookbook
Joomla! 1.5 Top Extensions Cookbook

Drupal 7
Drupal 7

PHP 5 E-commerce Development
PHP 5 E-commerce Development


Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software