Menu and Menubar

Table of Contents

Overview

Since 3.0

Menu and Menubar are navigation components that support various features and displaying options. They can have multiple submenu levels and the menu items can either trigger server actions or serve as links to external URLs. The main difference between Menu and Menubar is that Menu renders vertically, while Menubar renders horizontally.

See the ICEfaces Showcase Menu Live Demo, and Menubar Live Demo, complete with source code.

Getting Started

The <ace:submenu> and <ace:menuItem> tags are nested inside <ace:menu> and <ace:menubar> to design a menu hierarchy. The following is an example of a simple menu.

<ace:menu>
	<ace:submenu label="Actions">
		<ace:menuitem value="Action One" />
		<ace:menuitem value="Action Two" />
	</ace:submenu>
</ace:menu>
The above example simply renders a basic menu, but it doesn't execute any actions. Since <ace:menuItem> extends from UICommand, one can specify action and actionListener attributes. The following is an example with added functionality.

<ace:menu type="tiered">
	<ace:submenu label="Actions">
		<ace:menuitem value="Action One" action="#{bean.actionOne}" />
		<ace:menuitem value="Action Two" actionListener="#{bean.actionListenerTwo}" />
	</ace:submenu>
</ace:menu>

The example above, now displays the menu in a tiered format, and triggers action and actionListener events in the server when a menu item is clicked.

A Menu and Menubar can also be built programmatically by specifying a model for the menu. In the facelet one simply has to bind the model attribute to an object of type org.icefaces.ace.model.DefaultMenuModel, as the following example:

<ace:menu model="#{bean.model}" />

Then, in the bean one can proceed as follows to define the menu model:

public DefaultMenuModel model;

public void buildMenuModel() {
  	model = new DefaultMenuModel();
 	Submenu submenu = new Submenu();
 	screen1Menus.setId("submenu1");
 	screen1Menus.setLabel("Actions");
 	model.addSubmenu(submenu);
  	MenuItem menuItem1 = new MenuItem();
 	menuItem1.setId("menuitem1");
 	menuItem1.setValue("Action One");
 	menuItem1.setAction(actionOneBinding);
 	submenu.getChildren().add(menuItem1);
  	MenuItem menuItem2 = new MenuItem();
 	menuItem2.setId("menuitem2");
 	menuItem2.setValue("Action One");
 	menuItem2.setActionListener(actionListenerTwoBinding);
 	submenu.getChildren().add(menuItem2);
}

The code above would produce a menu like the second example. When building menus programmatically it is important to give ids to all submenus and menu items, and do so before setting any other attributes.

Attributes

TagLib Documentation
This section covers attributes involved in the typical use-cases for this component. For reference, the complete taglib documentation for the menu component is available here, and for the menuBar component here.
The Menu and Menubar components have some attributes in common. They are described below.

The widgetVar attribute is used to specify a Javascript variable name to access the widget in the client.

The model attribute is used to specify a DefaultMenuModel object to be used to build this menu.

The effect and effectDuration attributes are used to specify an effect to apply when displaying the submenus and menu items.

The style and styleClass attributes are applied to the container element of the menu.

The Menubar component has an autoSubmenuDisplay attribute that specifies whether the submenus and menu items are displayed on mouseover.

The Menu component has a tiered attribute that specifies whether the menu is displayed in different tiers.

It is also possible to specify style, styleClass and client-side onclick for a menu item.

JavaScript APIs / Client Behaviours

ICEfaces 3.x

The client side component object is exposed through the global variable name specified in the widgetVar attribute.

ICEfaces 4+

The "widgetVar" attribute on the ACE components has been removed in ICEfaces 4 and in its place a new "ice.ace.instance()" client JavaScript object lookup API has been introduced. The reason for this change is to enable lazy-initialization of the ACE component JavaScript objects to improve runtime performance and reduce browser memory use.

var widget = ice.ace.instance('frm:componentId);
The ice.ace.instance function requires the full client id of the component to be specified, such as "j_idt77:componentId" instead of just "componentId". To reduce the complexity of working with complete IDs with this function it may be preferable in some cases to use prependId="false" in the enclosing form (e.g. <h:form prependId="false">).
This component doesn't have a client-side API made specifically to be used by application developers. However, the component's internal methods and variables can be accessed in this way, including the underlying jQuery object and objects from underlying Javascript libraries (if applicable), and can be used for whatever purpose a developer might have in mind.

Keyboard and ARIA Support

Keyboard shortcuts and ARIA are supported as specified in the Wijmo documentation.

The following ARIA roles are supported: menu, menubar, menuitem

CSS Classes

The following markup represents the basic HTML structure of ace:menu and the CSS classes it uses.

<!-- Root container -->
<span>
	<div class="ui-widget ui-widget-content wijmo-wijmenu ui-corner-all ui-helper-clearfix [user defined classes]" style="[user defined styles]">
		<div class="scrollcontainer checkablesupport">
			<ul class="wijmo-wijmenu-list ui-helper-reset">
				<!-- Submenu -->
				<li class="ui-widget-header ui-corner-all"><h3>Submenu header</h3></li>
				<!-- Menu item -->
				<li class="ui-widget wijmo-wijmenu-item ui-state-default ui-corner-all">
					<a class="wijmo-wijmenu-link ui-corner-all">
						<span class="wijmo-wijmenu-text">
							<span class="ui-icon wijmo-wijmenu-icon-left"></span>
							<span class="wijmo-wijmenu-text">Menu item label</span>
						</span>
					</a>
				</li>
			</ul>
		</div>
	</div>
</span>

The following markup represents the basic HTML structure of ace:menuBar and the CSS classes it uses.

<!-- Root container -->
<div>
	<div class="ui-widget ui-widget-content wijmo-wijmenu ui-corner-all ui-helper-clearfix wijmo-wijmenu-horizontal [user defined classes]" style="[user defined styles]">
		<div class="scrollcontainer checkablesupport">
			<ul class="wijmo-wijmenu-list ui-helper-reset">
				<!-- 1st level menu item -->
				<li class="ui-widget wijmo-wijmenu-item ui-state-default ui-corner-all wijmo-wijmenu-parent">
					<a class="wijmo-wijmenu-link ui-corner-all">
						<span class="wijmo-wijmenu-text">
							<span class="ui-icon ui-icon-document wijmo-wijmenu-icon-left"></span>
							<span class="wijmo-wijmenu-text">Menu item label</span>
						</span>
						<span class="ui-icon ui-icon-triangle-1-s"></span>
					</a>
					<ul class="wijmo-wijmenu-list ui-widget-content ui-corner-all ui-helper-clearfix wijmo-wijmenu-child wijmo-wijmenu-flyout">
						<!-- 2nd level menu item -->
						<li class="ui-widget wijmo-wijmenu-item ui-state-default ui-corner-all wijmo-wijmenu-parent">
							<a class="wijmo-wijmenu-link ui-corner-all">
								<span class="wijmo-wijmenu-text">
									<span class="ui-icon ui-icon-contact wijmo-wijmenu-icon-left"></span>
									<span class="wijmo-wijmenu-text">Menu item label</span>
								</span>
								<span class="ui-icon ui-icon-triangle-1-e"></span>
							</a>
							<ul class="wijmo-wijmenu-list ui-widget-content ui-corner-all ui-helper-clearfix wijmo-wijmenu-child wijmo-wijmenu-flyout">
								<!-- 3rd level menu item -->
								<li class="ui-widget wijmo-wijmenu-item ui-state-default ui-corner-all">
									<a class="wijmo-wijmenu-link ui-corner-all">
										<span class="wijmo-wijmenu-text">
											<span class="wijmo-wijmenu-text">Menu item label</span>
										</span>
									</a>
								</li>
							</ul>
						</li>
					</ul>
				</li>
			</ul>
		</div>
	</div>
</div>

Menus and menu items (except for sliding menus) now take as much width as they need, instead of having a fixed width. If a fixed width is desired, it can be set by specifying a width in a CSS rule for the .wijmo-wijmenu class and also a rule for the following selector: .wijmo-wijmenu .wijmo-wijmenu-parent .wijmo-wijmenu-child. To change the width for sliding menus, the selector is .ice-ace-menu-sliding .wijmo-wijmenu-container.

Known Issues

Building menus from a model can create multiple different issues on the server side. To avoid these issues it is advised to always generate a new model object whenever the accessor method (e.g. getModel()) in the bean is invoked. So, instead of creating a single model object in the bean constructor, create a separate method that will build and return a new model object. This way, if multiple menu instances use the same model on a page or if the page has complex rendering/loading mechanisms that could keep a menu in the view while reloading it, then there won't be server-side errors related to having the same components in the view already, since when building a model one has to create the actual component instances.

There's a known issue when using MyFaces and building menus from a model. If the bean where the model is created is using a scope different than @SessionScope and the menu is not recreated at every request (e.g. only created in the constructor), then MyFaces will hand in a corrupt model object with loss of information to the component code. Visually, this looks like the menu disappears at the first dynamic update. The problem is related to serialization in MyFaces.
This situation can be fixed by adding the following markup in the deployment descriptor:

<context-param>
 <param-name>org.apache.myfaces.SERIALIZE_STATE_IN_SESSION</param-name>
 <param-value>false</param-value>
 </context-param>

Alternatively, if adding the above parameter is not possible. This problem can be avoided by simply using @SessionScope in the bean that creates the model object. If this is not possible either, another solution is to simply generate the model at every request (e.g. in the getter method for the model).

There seems to be an issue when using a custom style class, not overriding certain styles defined by the current theme, even though the custom style class is added correctly at the end of the 'class' attribute of the root container. The way to fix this is by either forcing rule precedence by adding the '!important' keyword at the end of each rule in the custom class or by simply making the custom class more specific, in order to make it have more precedence. For example, instead of '.myClass', define the custom class as 'div.myClass'.

Whenever a menu item is dynamically changed, without updating the entire menu in which it is, it may appear to lose some styling and behaviour. This is so, because the nodes corresponding to the menu item were replaced without re-initializing the whole menu on the client, which applies additional styling and behaviour. For these cases, simply set the forceMenuUpdate attribute to true in an event listener when the change in the menu item occurs, and the whole menu will be updated to keep all the necessary styling and bahaviour for the menu to work properly. This attribute will be automatically set back to false by the component after being consumed.

Other Resources

Wijmo Menu Documentation

Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.

© Copyright 2021 ICEsoft Technologies Canada Corp.