Fusion Middleware Documentation
Advanced Search


Developing Web User Interfaces with Oracle ADF Faces
Close Window

Table of Contents

Show All | Collapse

20 Working with Navigation Components

This chapter describes how to use ADF Faces navigation components to provide navigation in web user interfaces. This includes descriptions of how to use buttons and links to navigate and invoke functionality in addition to how to create page hierarchies. The chapter also describes how to use train components to navigate a multistep process.

This chapter includes the following sections:

20.1 About Navigation Components

Navigation components allow users to drill down for more information, to navigate to related pages or windows, and to perform specific actions on data and navigate at the same time. The common forms of navigation components are buttons and links, most of which can be used on their own and a few that can only be used in conjunction with other components.

Some components render navigable items such as tabs and breadcrumbs for navigating hierarchical pages and keeping track of the user's current location in the page hierarchy. Two components render links and buttons that you use specifically to guide users through a multistep task. You can also use the button or link components to fire partial page requests, and to implement popup dialogs and secondary windows (in conjunction with other ADF Faces tags and components). Navigation components can provide navigation with or without server-side actions.

Figure 20-1 shows the different ADF Faces components that are used to provide navigation.

Figure 20-1 ADF Faces Navigation Components

ADF Faces navigation components

20.1.1 Navigation Components Use Cases and Examples

Typical uses of navigation components are to create buttons and links to allow users to navigate to another page or window, to perform actions on data, or to perform actions and navigate at the same time. For example, as shown in Figure 20-2, the main page of the File Explorer application contains a button component that you click to refresh the page after making a skin selection and a link component that opens a popup window when clicked.

Figure 20-2 File Explorer Application Main Page

Main page of File Explorer application

At the top right corner of the File Explorer application, there are four global application links. While you can use link components to provide the destinations for navigation, the File Explorer application uses the navigationPane and child commandNavigationItem components to provide links that either navigate directly to another location or deliver an action that results in navigation.

The navigationPane component also lets you organize application content in a meaningful structure and provides a navigation method for users to move through different content areas in the application to perform various functions. For example, a simple HR application might have pages that let employees check on company benefits, and pages for administration to view and create employee data, as shown in Figure 20-3. The navigationPane component provides the structure with tabs, bars, or lists for example, and the child commandNavigationItem components provide the navigation links.

Figure 20-3 Page Showing Navigation Tab, Bar and List Links

Navigation tabs, bars and lists on page

The navigationPane component can also be used with a menu model, where the component is bound to the menu model managed bean. For complex page hierarchies, using a menu model is more efficient as the framework generates the correct number of navigation items in the structure on each page and also keeps track of which items are to be displayed as "selected".

The menuBar component can also be bound to a menu model to implement menus and submenus for navigating different levels in a page hierarchy. Most shopping websites use a system of menus to categorize shopping areas and provide a one-click action to a specific subcategory or item in the hierarchy. As shown in Figure 20-4, the menu bar shows the first level of menu items at a glance. As the mouse cursor hovers over a menu, a submenu of more items display for the user to browse and choose. Typically you would not implement more than three levels of menu items.

Figure 20-4 Page With Three Menus on a Bar with a Submenu Expanded

Page With Three Menus On a Bar with a Submenu Expanded

Whether you use navigationPane or menuBar (bound to a menu model) to create your page hierarchy, you can use the breadCrumbs component and a series of child commandNavigationItem components to provide users with a visual indication to their current location in the page hierarchy. As shown in Figure 20-5, the breadCrumbs component displays a line of text links starting from the root page down to the current page, which is always the last link. If you create your page hierarchy using a menu model, you can also bind the breadCrumbs component to the same menu model managed bean and let the framework dynamically generate the links for you.

Figure 20-5 Page Showing Horizontal Breadcrumb Links

Page showing breadcrumb links

The train component allows users to quickly see where they are in a multistep process and also navigate through that process. The trainButtonBar component provides additional navigation for a train process in the form of Back and Next buttons, as shown in Figure 20-6.

Figure 20-6 ADF Faces Train and TrainButtonBar Demonstration Pages

Train and TrainButtonBar components

20.1.2 Additional Functionality for Navigation Components

You may find it helpful to understand other ADF Faces features before you implement your navigation components. Additionally, once you have added these components to your page, you may find that you need to add functionality such as accessibility and localization. Following are links to other functionality that navigation components can use.

20.2 Common Functionality in Navigation Components

Like any JSF application, an application that uses ADF Faces components contains a set of rules for choosing the next page to display when a button or link (used on its own or within another navigation component) is clicked. You define the rules by adding JSF navigation rules and cases in the application's configuration resource file (faces-config.xml).

JSF uses an outcome string to select the navigation rule to use to perform a page navigation. ADF Faces navigation components that implement javax.faces.component.ActionSource interface generate an ActionEvent event when users activate the component. The JSF NavigationHandler and default ActionListener mechanisms use the outcome string on the activated component to find a match in the set of navigation rules. When JSF locates a match, the corresponding page is selected, and the Render Response phase renders the selected page. For more information about the JSF lifecycle, see Chapter 5, "Using the JSF Lifecycle with ADF Faces." Also note that navigation in an ADF Faces application may use partial page rendering. For more information, see Chapter 8, "Rerendering Partial Page Content."

20.3 Using Buttons and Links for Navigation

ADF Faces provides button and link components that can be used for navigation. Depending on your use case, you can configure these components to navigate directly to another location, to submit requests, and fire ActionEvent events.

Apart from the button and link components, ADF Faces also provides specialized components (goMenuItem and commandMenuItem) for use inside menus. For more information, see Chapter 16, "Using Menus, Toolbars, and Toolboxes."

The button and link components can render images, along with optional text, as shown in Figure 20-7 and Figure 20-8. You can determine the position of the image relative to the optional text by setting a value for the iconPosition attribute. In addition, you can set different icons for when the user hovers over an icon, or the icon is depressed or disabled. You specify the image to use by setting a value for the icon attribute. The button and link components expand to the number of pixels required to accommodate the image that you specify to render within the component. If you do not specify an image, the component renders using the minimum dimensions specified for the component in the web application's skin.

Figure 20-7 shows a number of the options that you can configure for the button component.

Figure 20-7 ADF Faces button Component

ADF Faces button Component

Figure 20-8 shows a number of the options that you can configure for the link component.

Figure 20-8 ADF Faces link Component

ADF Faces link Component

Using the ADF Faces toolbar component, you can provide additional functionality, such as a popup facet that opens popup menus from a button component. For more information, see Section 16.3, "Using Toolbars."

The behavior of button and link components differ when you output your page in simplified mode for printing or email. The link component appears in print and email modes although it cannot be invoked while the button component does not render when you output a page in simplified mode for printing or email. For more information about email and print output modes, see Chapter 37, "Using Different Output Modes."

You can configure your application to allow end users to invoke a browser's context menu when they right-click an action component that renders a link. End users who right-click the link rendered by an action component may use a browser's context menu to invoke an action that you do not want them to invoke (for example, open the link in a new window). For more information, see Section 20.4, "Configuring a Browser's Context Menu for Links."

You can show a warning message to end users if the page that they attempt to navigate away from contains uncommitted data. Add the checkUncommittedDataBehavior component as a child to action components that have their immediate attribute set to true. If the user chooses not to navigate, the client event will be cancelled. You can add the checkUncommittedDataBehavior component as a child to the af:button and af:link components. For the warning message to appear to end users, the page must contain uncommitted data and you must have also set the document tag's uncommittedDataWarning attribute to on, as described in Section 9.2.5, "How to Configure the document Tag."

Note:

A warning message may also appear for uncommitted data if you set the document tag's uncommittedDataWarning tag to on and your page renders an ADF Controller bounded task flow that is configured as critical, as described in the "How to Enable Implicit Save Points" section in Developing Fusion Web Applications with Oracle Application Development Framework.

20.3.1 How to Use Buttons and Links for Navigation and Deliver ActionEvents

Typically, you use action components like button and link to perform page navigation and to execute any server-side processing.

Before you begin:

It may help to understand how action component's attributes affect functionality. For more information, see Section 20.3, "Using Buttons and Links for Navigation."

You may also find it helpful to understand functionality that can be added using other ADF Faces features. For more information, see Section 20.1.2, "Additional Functionality for Navigation Components."

To create and use action components:

  1. In the Components window, from the General Controls panel, drag and drop the action component that you want to use onto the JSF page. More specifically, drag and drop a:

    • Button to create a button component.

    • Link to create a link component.

  2. In the Properties window, expand the Common section and set the following:

    • Text: Specify the text to display.

      Tip:

      Alternatively, you can use the textAndAccessKey attribute to provide a single value that defines the label along with the access key to use for the button or link. For information about how to define access keys, see Section 33.3.4, "How to Define Access Keys for an ADF Faces Component."

    • Icon: Set to the URI of the image file if you want to render an icon inside the component. If you render an icon, you can also set values for hoverIcon, disabledIcon, depressedIcon, and iconPosition in the Appearance section.

      Tip:

      You can use either the text attribute (or textAndAccessKey attribute) or the icon attribute, or both.

    • IconPosition: If you specified an icon, you can determine the position of the icon relative to the text by selecting a value from the dropdown list:

      • <default> (leading): Renders the icon before the text.

      • trailing: Renders the icon after the text.

      • top: Renders the icon above the text.

      • bottom: Renders the icon below the text.

    • Selected: Set to true so that the component appears as selected when the page renders.

    • Action: Set to an outcome string or to a method expression that refers to a backing bean action method that returns a logical outcome String. For more information about configuring the navigation between pages, see Section 3.3, "Defining Page Flows."

      The default JSF ActionListener mechanism uses the outcome string to select the appropriate JSF navigation rule, and tells the JSF NavigationHandler what page to use for the Render Response phase. For more information about using managed bean methods to open dialogs, see Chapter 15, "Using Popup Dialogs, Menus, and Windows." For more information about outcome strings and navigation in JSF applications, see the Java EE 6 tutorial at http://docs.oracle.com/javaee/index.html.

      Tip:

      The actionListener attribute can also be used for navigation when bound to a handler that returns an outcome. Usually, you should use this attribute only to handle user interface logic and not navigation.

      For example, in the File Explorer application, the Search button in Search panel does not navigate anywhere. Instead, it performs a search. It has the following value for its actionListener attribute:

      actionListener="#{explorer.navigatorManager.searchNavigator.
                                                 searchForFileItem}"
      

      This expression evaluates to a method that actually performs the search.

  3. Expand the Behavior section and set the following:

    • Disabled: Select true from the dropdown list if you want to show the component as a noninteractive button or link.

    • PartialSubmit: Select true from the dropdown list to fire a partial page request each time the component is activated. For more information, see Section 8.2, "Using Partial Triggers."

    • Immediate: Select true from the dropdown list if you want to skip the Process Validations and Update Model phases. The component's action listeners (if any), and the default JSF ActionListener handler are executed at the end of the Apply Request Values phase of the JSF lifecycle. For more information, see Section 5.2, "Using the Immediate Attribute."

  4. Optionally, if you set the immediate attribute to true as described in Step 3, you can add the af:checkUncommittedDataBehavior component as a child to the action component to display a warning message to the user if the page contains uncommitted data. Drag Check Uncommitted Data Behavior from the Behavior group in the Operations panel of the Components window and drop it as a child of the action component you added in Step 1.

    Note:

    You must have also set the document tag's uncommittedDataWarning attribute to on, as described in Section 9.2.5, "How to Configure the document Tag."

Buttons and links can also be used to open secondary windows through these attributes: useWindow, windowHeight, windowWidth, launchListener, and returnListener. For information about opening secondary windows, see the "Using the ADF Faces Dialog Framework Instead of Bounded Task Flows" section in Developing Fusion Web Applications with Oracle Application Development Framework.

To use buttons and links to invoke popups without writing any JavaScript code, see Section 15.3, "Declaratively Invoking a Popup."

20.3.2 How to Use Buttons and Links for Navigation Without Delivering ActionEvents

You can use the button and link components to perform direct page navigation, without delivering an ActionEvent event.

Before you begin:

It may help to understand how the button and link components' attributes affect functionality. For more information, see Section 20.3, "Using Buttons and Links for Navigation."

You may also find it helpful to understand functionality that can be added using other ADF Faces features. For more information, see Section 20.1.2, "Additional Functionality for Navigation Components."

To create buttons and links that navigate without delivering an ActionEvent:

  1. In the Components window, from the General Controls panel, drag and drop the component that you want to use onto the JSF page. More specifically, drag and drop a:

    • Button to create a button component.

    • Link to create a link component.

  2. In the Properties window, expand the Common section and set the following:

    • Text: Specify the text to display.

      Tip:

      Instead, you can use the textAndAccessKey attribute to provide a single value that defines the label and the access key to use for the button or link. For information about how to define access keys, see Section 33.3.4, "How to Define Access Keys for an ADF Faces Component."

    • Icon: Set to the URI of the image file if you want to render an icon inside the component. If you render an icon, you can also set values for hoverIcon, disabledIcon, depressedIcon, and iconPosition in the Appearance section.

      Tip:

      You can use either the text attribute (or textAndAccessKey attribute) or the icon attribute, or both.

    • IconPosition: If you specified an icon, you can determine the position of the icon relative to the text by selecting a value from the dropdown list:

      • <default> (leading): Renders the icon before the text.

      • trailing: Renders the icon after the text.

      • top: Renders the icon above the text.

      • bottom: Renders the icon below the text.

    • Selected: Set to true so that the component appears as selected when the page renders.

    • Destination: Set to the URI of the page to navigate to.

      For example, set to the following to navigate to Oracle's web site:

      destination="http://www.oracle.com"
      
    • TargetFrame: Specify where the new page should display by selecting a value from the dropdown list:

      • _blank: The link opens the document in a new window.

      • _parent: The link opens the document in the window of the parent. For example, if the link appeared in a dialog, the resulting page would render in the parent window.

      • _self: The link opens the document in the same page or region.

      • _top: The link opens the document in a full window, replacing the entire page.

  3. Expand the Behavior section and select true from the Disabled dropdown list if you want to show the component as a noninteractive button or link.

20.3.3 What You May Need to Know About Using Partial Page Navigation

As described in Section 8.5, "Using Partial Page Navigation," you can configure an ADF Faces application to have navigation triggered through a partial page rendering request. When partial page navigation is turned on, partial page navigation for GET requests is automatically supported on the following components:

  • af:button

  • af:link

  • af:goMenuItem (used within af:menu and af:menuBar)

  • af:commandNavigationItem (used within af:navigationPane)

The only requirement is that the destination attribute on a supported component contain a relative URL of the application context root and begin with "/", such as "/faces/myPage.jsf", where faces is the URL mapping to the application's servlet defined in web.xml and myPage.jsf is the page to navigate. Because partial page navigation makes use of the hash ('#') portion of the URL, you cannot use the hash portion for navigation to anchors within a page.

If the targetFrame attribute on a supported component is set to open the link in a new window, the framework automatically reverts to full page navigation.

20.4 Configuring a Browser's Context Menu for Links

The action components that render links at runtime allow your end users to invoke actions. In addition you can configure your application so that the ADF Faces framework allows the end user's browser to render a context menu for these action components. By default, the ADF Faces framework disables this context menu. The ADF Faces framework disables this context menu when no value is set for the destination attribute because the context menu may present menu options that invoke a different action (for example, open a link in a new window) to that specified by the action component. The components for which you can configure this behavior include the following:

  • af:link

  • af:commandMenuItem (used within an af:menuBar component)

  • af:commandNavigationItem if no value is specified for the destination attribute, the ADF Faces framework enables the browser context menu in the following scenarios:

    • For the two anchors that af:commandNavigationItem renders when inside an af:train component

    • When an af:commandNavigationItem renders inside an af:breadCrumbs component

    • When an af:commandNavigationItem renders inside an af:navigationPane component (any hint--tabs, bar, buttons, choice, list)

  • af:panelTabbed: the tabs and overflow indicators

  • af:panelAccordion: the disclosure link and overflow indicators

You cannot configure this behavior for components that specify a destination and do not invoke an action. For example, an af:commandNavigationItem component where you specify a value for the destination attribute and no value for the action attribute.

20.4.1 How to Configure a Browser's Context Menu for Command Links

Set the value of the oracle.adf.view.rich.ACTION_LINK_BROWSER_CONTEXT_SUPPRESSION context parameter in your application's web.xml file to no.

Before you begin:

It may help to understand what action components you can configure this functionality for. For more information, see Section 20.4, "Configuring a Browser's Context Menu for Links."

You may also find it helpful to understand functionality that can be added using other ADF Faces features. For more information, see Section 20.1.2, "Additional Functionality for Navigation Components."

To configure a browser's context menu for a command link:

  1. In the Applications window, expand the WEB-INF node and double-click web.xml.

  2. In the overview editor, click the Application navigation tab and then click the Add icon next to the Context Initialization Parameters table to add an entry for the oracle.adf.view.rich.ACTION_LINK_BROWSER_CONTEXT_SUPPRESSION parameter and set it to no.

  3. Save and close the web.xml file.

20.4.2 What Happens When You Configure a Browser's Context Menu for Command Links

If you followed the procedure outlined in Section 20.4.1, "How to Configure a Browser's Context Menu for Command Links," JDeveloper writes a value to the web.xml file, as shown in Example 20-1.

Example 20-1 Context Parameter to Configure a Browser's Context Menu

<context-param>
    <param-name>oracle.adf.view.rich.ACTION_LINK_BROWSER_CONTEXT_SUPPRESSION</param-name>
    <param-value>no</param-value>
  </context-param>

For more information about ADF Faces configuration options in your application's web.xml file, see Section A.2, "Configuration in web.xml."

At runtime, end users can invoke a browser's context menu by right-clicking on the links rendered by certain components, as described in Section 20.4, "Configuring a Browser's Context Menu for Links."

20.5 Using Buttons or Links to Invoke Functionality

In addition to using action components for navigation, ADF Faces also includes listener tags that you can use with action components to have specific functionality execute when the action event fires. Listener tags included with ADF Faces include:

20.5.1 How to Use an Action Component to Download Files

You can create a way for users to download files by creating an action component such as a button and associating it with a fileDownloadActionListener tag. When the user selects or clicks the component, a popup dialog displays that allows the user to select different download options, as shown in Figure 20-9.

Figure 20-9 File Download Dialog

File download dialog

Use the fileDownloadActionListener tag to allow an action component (for example, a button, link, or menu item) to send the contents of a file to an end user. You can also specify the content type or file name when you use this tag. Any value that you set for the action component's partialSubmit attribute is ignored at render time if you use the fileDownloadActionListener tag. The fileDownloadActionListener tag determines what type of submit the action component invokes based on the context. If you use the fileDownloadActionListener tag within a JSF portlet in your application, the action component invokes a partial submit (partialSubmit="true"). If you use the fileDownloadActionListener tag within an application that uses the ADF Faces servlet, the action component invokes a full submit (partialSubmit="false").

Tip:

For information about uploading a file to the server, see Section 11.9, "Using File Upload."

After the content has been sent to the browser, how that content is displayed or saved depends on the option that the end user selects in the dialog. If the end user selects the Open with option, the application associated with that file type will be invoked to display the content. For example, a text file may result in the Notepad application being started. If the end user selects the Save to Disk option, depending on the browser, a popup dialog may appear to select a file name and a location in which to store the content.

Example 20-2 shows the tags of a button with the fileDownloadActionListener tag to download the file named hello.txt to the user.

Example 20-2 File Download Using Button and fileDownloadActionListener Tag

<af:button value="Say Hello">
  <af:fileDownloadActionListener filename="hello.txt"
      contentType="text/plain; charset=utf-8"
      method="#{bean.sayHello}"/>
</af:button>

Example 20-3 shows a managed bean method used to process the file download.

Example 20-3 Managed Bean Method Used to Process File Download

public void sayHello(FacesContext context, OutputStream out) throws IOException{
  OutputStreamWriter w = new OutputStreamWriter(out, "UTF-8");
  w.write("Hi there!");
   . . .
}

If you use the fileDownloadActionListener tag from within a JSF portlet in your application, you can optionally add the parameters described in Table 20-1 to the web.xml file of your application to configure the size and temporary location options for the file during download.

Table 20-1 Parameters to Add to web.xml File to Use fileDownloadActionListener in a Portlet

Parameter name Data type Description

oracle.adf.view.rich.portal.FILE_DOWNLOAD_MAX_MEM

Integer

Specify the maximum size in kilobytes of the file that the fileDownloadActionListener tag can store during a session. If the file exceeds the maximum size you specify, the application attempts to save the file to the hard drive in the location you specify for FILE_DOWNLOAD_TEMP_DIR.

If you do not specify a value for this parameter in the web.xml file, it defaults to 100 kilobytes.

oracle.adf.view.rich.portal.FILE_DOWNLOAD_MAX_DISK_SPACE

Integer

Specify the maximum size in kilobytes of the file that the fileDownloadActionListener tag can download. If a file's size exceeds this value, an exception occurs and a log message is logged to the server's log file.

If you do not specify a value for this parameter in the web.xml file, it defaults to 2000.

oracle.adf.view.rich.portal.FILE_DOWNLOAD_TEMP_DIR

String

Specify the temporary location where you store files during download. If you do not specify a value, it defaults to the directory specified by java.io.tempDir.


For more information about configuring your web.xml file, Section A.2, "Configuration in web.xml." For information about how to create a JSF portlet, see the Oracle Fusion Middleware Developer's Guide for Oracle WebCenter.

Before you begin:

It may help to understand how a component's attributes affect functionality. For more information, see Section 20.5, "Using Buttons or Links to Invoke Functionality."

You may also find it helpful to understand functionality that can be added using other ADF Faces features. For more information, see Section 20.1.2, "Additional Functionality for Navigation Components."

You will need to complete this task:

Create an action component, as described in Section 20.3, "Using Buttons and Links for Navigation."

To create a file download mechanism:

  1. In the Components window, from the Operations panel, in the Listeners group, drag and drop the File Download Action Listener tag as a child to the action component.

  2. In the Properties window set the following attributes:

    • ContentType: Specify the MIME type of the file, for example text/plain, text/csv, application/pdf, and so on.

    • Filename: Specify the proposed file name for the object. When the file name is specified, a Save File dialog will typically be displayed, though this is ultimately up to the browser. If the name is not specified, the content will typically be displayed inline in the browser, if possible.

    • Method: Specify the method that will download the file contents. The method takes two arguments, a FacesContext object and an OutputStream object. The OutputStream object will be automatically closed, so the sole responsibility of this method is to write all bytes to the OutputStream object.

    For example, entries in the JSF page for a button component that uses the fileDownloadActionListener tag would be similar to the following:

    <af:button text="Load File">
      <af:fileDownloadActionListener contentType="text/plain"
          filename="MyFile.txt"
          method="#(mybean.LoadMyFile"/>
    </af:button>
    

20.5.2 How to Use an Action Component to Reset Input Fields

You can use the resetListener tag in conjunction with an action component to reset input values. When the end user invokes the action component, it resets all input values to null or empty. If you want to reset the input components to their previous state, which was partially or fully submitted successfully to the server, then you should use a reset button. For more information, see Section 11.2.3, "How to Add a Button to Reset the Form."

If you use the resetListener tag to reset input components that render in a popup, you also need to set a value for the popup component's resetEditableValues property. For more information about this use case, see Section 15.7, "Resetting Input Fields in a Popup."

Before you begin:

It may help to understand how an action component's attributes affect functionality. For more information, see Section 20.5, "Using Buttons or Links to Invoke Functionality."

You may also find it helpful to understand functionality that can be added using other ADF Faces features. For more information, see Section 20.1.2, "Additional Functionality for Navigation Components."

You will need to complete this task:

Create an action component, as described in Section 20.3, "Using Buttons and Links for Navigation."

To use the reset listener tag:

  1. In the Components window, from the Operations panel, in the Listeners group, drag a Reset Listener and drop it inside the action component that you created.

  2. In the Insert Reset Listener dialog, specify the type of event that the resetListener tag activates in response to. For example, enter action so that the resetListener tag responds to an actionEvent returned by the action component's actionListener attribute.

    Click Help in the Insert Reset Listener dialog to view a complete list of supported values.

20.6 Using Navigation Items for a Page Hierarchy

Note:

If your application uses the Fusion technology stack with ADF Controller, then you should use ADF task flows and an XMLMenuModel implementation to create the navigation system for your application page hierarchy. For details, see the "Creating a Page Hierarchy Using Task Flows" section in Developing Fusion Web Applications with Oracle Application Development Framework.

An application may consist of pages that are related and organized in a tree-like hierarchy, where users gain access to specific information on a page by drilling down a path of links. For example, Figure 20-10 shows a simple page hierarchy with three levels of nodes under the top-level node, Home. The top-level node represents the root parent page; the first-level nodes, Benefits and Employee Data, represent parent pages that contain general information for second-level child nodes (such as Insurance and View Employee) that contain more specific information; the Insurance node is also a parent node, which contains general information for third-level child nodes, Health and Dental. Each node in a page hierarchy (except the root Home node) can be a parent and a child node at the same time, and each node in a page hierarchy corresponds to a page.

Figure 20-10 Benefits and Employee Page Hierarchy

Hierarchical page tree. 2 level 1 nodes, 1 global node.

Navigation in a page hierarchy follows the parent-child links. For example, to view Health information, the user would start drilling from the Benefits page, then move to the Insurance page where two choices are presented, one of which is Health. The path of selected links starting from Home and ending at Health is known as the focus path in the tree.

In addition to direct parent-child navigation, some cross-level or cross-parent navigation is also possible. For example, from the Dental page, users can jump to the Paid Time Off page on the second level, and to the Benefits page or the Employee Data page on the first level.

As shown in Figure 20-10, the Help node, which is not linked to any other node in the hierarchy but is on the same level as the top-level Home node, is a global node. Global nodes represent global pages (such as a Help page) that can be accessed from any page in the hierarchy.

Typical widgets used in a web user interface for navigating a page hierarchy are tabs, bars, lists, and global links, all of which can be created by using the navigationPane component. Figure 20-11 shows an example of how the hierarchy as illustrated in Figure 20-10 could be rendered using the navigationPane and other components.

Figure 20-11 Rendered Benefits and Employee Data Pages

Hiearchical menu components in a page

In general, tabs are used as first-level nodes, as shown in Figure 20-11, where there are tabs for the Benefits and Employee Data pages. Second-level nodes, such as Insurance and Paid Time Off are usually rendered as bars, and third-level nodes, such as Health and Dental are usually rendered as lists. However, you may also use tabs for both first- and second-level nodes. Global links (which represent global nodes) are rendered as text links. In Figure 20-11, the Home and Help global links are rendered as text links.

One navigationPane component corresponds to one level of nodes, whether they are first-, second-, or third-level nodes, or global nodes. Regardless of the type of items the navigationPane component is configured to render for a level, you always use the commandNavigationItem component to represent the items within the level.

The navigationPane component simply renders tabs, bars, lists, and global links for navigation. To achieve the positioning and visual styling of the page background, as shown in Figure 20-16 and Figure 20-17, you use the decorativeBox component as the parent to the first level navigationPane component. The decorativeBox component uses themes and skinning keys to control the borders and colors of its different facets. For example, if you use the default theme, the decorativeBox component body is white and the border is blue, and the top-left corner is rounded. If you use the medium theme, the body is a medium blue. For information about using themes and skins, see Chapter 31, "Customizing the Appearance Using Styles and Skins".

Tip:

Because creating a page hierarchy requires that each page in the hierarchy use the same layout and look and feel, consider using a template to determine where the navigation components should be placed and how they should be styled. For more information, see Section 10.3, "Using Page Templates".

On each page in simple hierarchies, you first use a series of navigationPane components to represent each level of the hierarchy. Then you add commandNavigationItem components as direct children of the navigationPane components for each of the links at each level. For example, to create the Health insurance page as shown in Figure 20-11, you would first use a navigationPane component for each level displayed on the page, in this case it would be four: one for the global links, one for the first-level nodes, one for the second-level nodes, and one for the third-level nodes. You would then need to add commandNavigationItem components as children to each of the navigationPane components to represent the individual links (for example, you would add two commandNavigationItem child components to the third-level navigationPane component to represent the two third-level list items). If instead you were creating the Benefits page, as shown in Figure 20-12, you would add only three navigationPane components (one each for the global, first, and second levels), and then add just the commandNavigationItem components for the links seen from this page.

Figure 20-12 First-Level Page

Tabs navigate to first level page

As you can see, with large page hierarchies, this process can be very time consuming and error prone. Instead of creating each of the separate commandNavigationItem components on each page, for larger hierarchies you can use an XMLMenuModel implementation and managed beans to dynamically generate the navigation items on the pages. The XMLMenuModel class, in conjunction with a metadata file, contains all the information for generating the appropriate number of hierarchical levels on each page, and the navigation items that belong to each level.

Then instead of using multiple commandNavigationItem components within each navigationPane component and marking the current items as selected on each page, you declaratively bind each navigationPane component to the same XMLMenuModel implementation, and use one commandNavigationItem component in the nodeStamp facet to provide the navigation items. The commandNavigationItem component acts as a stamp for navigationPane component, stamping out navigation items for nodes (at every level) held in the XMLMenuModel object.

The menuBar component can also be used with the XMLMenuModel implementation to stamp out menu items for navigating a page hierarchy.

Note:

If you want to create menus that can be used to cause some sort of change in an application (for example, a File menu that contains the commands Open and Delete), then see Chapter 16, "Using Menus, Toolbars, and Toolboxes".

On any page, to show the user's current position in relation to the entire page hierarchy, you use the breadCrumbs component with a series of commandNavigationItem components or one commandNavigationItem component as a nodeStamp, to provide a path of links from the current page back to the root page (that is, the current nodes in the focus path).

For more information about creating a navigational hierarchy using the XMLMenuModel, see Section 20.7, "Using a Menu Model to Create a Page Hierarchy". For more information about manually creating a navigational hierarchy, see Section 20.8, "Creating a Simple Navigational Hierarchy".

20.6.1 How to Create Navigation Cases for a Page Hierarchy

Whether you use a menu model to create the navigation items for a page hierarchy or manually create the navigation items yourself, the JSF navigation model, through the default ActionListener mechanism, is used to choose the page to navigate to when users select a navigation item.

Before you begin:

It may help to understand how the attributes of navigation components affect functionality. For more information, see Section 20.6, "Using Navigation Items for a Page Hierarchy."

You may also find it helpful to understand functionality that can be added using other ADF Faces features. For more information, see Section 20.1.2, "Additional Functionality for Navigation Components."

To create navigation cases for a page hierarchy:

  1. In the Applications window, expand the WEB-INF node and double-click faces-config.xml.

  2. Create one global JSF navigation rule that has the navigation cases for all the nodes in the page hierarchy.

    For example, the page hierarchy shown in Figure 20-10 has 10 nodes, including the global Help node. Thus, you would create 10 navigation cases within one global navigation rule in the faces-config.xml file, as shown in Example 20-4.

    For each navigation case, specify a unique outcome string, and the path to the JSF page that should be displayed when the navigation system returns an outcome value that matches the specified string.

    Example 20-4 Global Navigation Rule for a Page Hierarchy in faces-config.xml

    <navigation-rule>
      <navigation-case>
        <from-outcome>goHome</from-outcome>
        <to-view-id>/home.jsf</to-view-id>
      </navigation-case>
      <navigation-case>
        <from-outcome>goHelp</from-outcome>
        <to-view-id>/globalhelp.jsf</to-view-id>
      </navigation-case>
      <navigation-case>
        <from-outcome>goEmp</from-outcome>
        <to-view-id>/empdata.jsf</to-view-id>
      </navigation-case>
      <navigation-case>
        <from-outcome>goBene</from-outcome>
        <to-view-id>/benefits.jsf</to-view-id>
      </navigation-case>
      <navigation-case>
        <from-outcome>goIns</from-outcome>
        <to-view-id>/insurance.jsf</to-view-id>
      </navigation-case>
      <navigation-case>
        <from-outcome>goPto</from-outcome>
        <to-view-id>/pto.jsf</to-view-id>
      </navigation-case>
      <navigation-case>
        <from-outcome>goView</from-outcome>
        <to-view-id>/viewdata.jsf</to-view-id>
      </navigation-case>
      <navigation-case>
        <from-outcome>goCreate</from-outcome>
        <to-view-id>/createemp.jsf</to-view-id>
      </navigation-case>
      <navigation-case>
        <from-outcome>goHealth</from-outcome>
        <to-view-id>/health.jsf</to-view-id>
      </navigation-case>
      <navigation-case>
        <from-outcome>goDental</from-outcome>
        <to-view-id>/dental.jsf</to-view-id>
      </navigation-case>
    </navigation-rule>
    

For more information about creating navigation cases in JDeveloper, see Section 3.3, "Defining Page Flows."

20.7 Using a Menu Model to Create a Page Hierarchy

Note:

If your application uses the Fusion technology stack or ADF Controller, then you should use ADF task flows and an XMLMenuModel implementation to create the navigation system for your application page hierarchy. For details, see the "Creating a Page Hierarchy Using Task Flows" section in Developing Fusion Web Applications with Oracle Application Development Framework.

Section 20.6, "Using Navigation Items for a Page Hierarchy" describes how you can create navigation items for a very simple page hierarchy using navigationPane components with multiple commandNavigationItem children components. Using the same method for more complex page hierarchies would be time consuming and error prone. It is inefficient and tedious to manually insert and configure individual commandNavigationItem components within navigationPane and breadCrumbs components on several JSF pages to create all the available items for enabling navigation. It is also difficult to maintain the proper selected status of each item, and to deduce and keep track of the breadcrumb links from the current page back to the root page.

For more complex page hierarchies (and even for simple page hierarchies), a more efficient method of creating a navigation system is to use a menu model. A menu model is a special kind of tree model. A tree model is a collection of rows indexed by row keys. In a tree, the current row can contain child rows (for more information about a tree model, see Section 12.6, "Displaying Data in Trees"). A menu model is a tree model that knows how to retrieve the rowKey of the node that has the current focus (the focus node). The menu model has no special knowledge of page navigation and places no requirements on the nodes that go into the tree.

The XMLMenuModel class creates a menu model from a navigation tree model. But XMLMenuModel class has additional methods that enable you to define the hierarchical tree of navigation in XML metadata. Instead of needing to create Java classes and configuring many managed beans to define and create the menu model (as you would if you used one of the other ADF Faces menu model classes), you create one or more XMLMenuModel metadata files that contain all the node information needed for the XMLMenuModel class to create the menu model.

Tip:

Do not confuse the navigationPane component with the panelTabbed component. You use the panelTabbed component to display multiple tabbed content areas that can be hidden and displayed (see Section 9.10, "Displaying or Hiding Contents in Panels"). However, the panelTabbed component cannot bind to any navigational model and the whole content must be available from within the page, so it has limited applicability.

To create a page hierarchy using a menu model, you do the following:

20.7.1 How to Create the Menu Model Metadata

The XMLMenuModel metadata file is a representation of a navigation menu for a page hierarchy in XML format. You can use one or more XMLMenuModel metadata files to represent an entire page hierarchy. In an XMLMenuModel metadata file, the page hierarchy is described within the menu element, which is the root element of the file. Every XMLMenuModel metadata file is required to have a menu element and only one menu element is allowed in each file.

The other elements in the XMLMenuModel metadata file or hierarchy can be made up of item nodes, group nodes, and shared nodes. Item nodes represent navigable nodes (or pages) in the hierarchy. For example, say you wanted to build the hierarchy depicted in Figure 20-13.

Figure 20-13 Sample Page Hierarchy

Hierarchy for a navigation menu

If you wanted each node in the hierarchy to have its own page to which a user can navigate, then in the metadata file you would create an item node for each page. You nest children nodes inside a parent node to create the hierarchy. However, say you did not need a page for the Employee Data node, but instead wanted the user to navigate directly to the View Employee page. You would then use a group node to represent the Employee Data page and use the group node's idref attribute to reference the page that opens (the View Employee page) when an end user clicks the Employee Data tab. The group node allows you to retain the hierarchy without needing to create pages for nodes that are simply aggregates for their children nodes.

Example 20-5 shows an XMLMenuModel metadata file that uses mostly item nodes and one group node to define the entire page hierarchy illustrated in Figure 20-13.

Example 20-5 XMLMenuModel Metadata File Sample 1

<?xml version="1.0" encoding="windows-1252" ?>
<menu xmlns="http://myfaces.apache.org/trinidad/menu">
  <itemNode id="in01" focusViewId="/home.jsf" label="Home" action="goHome">
    <itemNode id="in1" focusViewId="/benefits.jsf" action="goBene"
              label="Benefits">
      <itemNode id="in11" focusViewId="/insurance.jsf" action="goIns"
                label="Insurance">
        <itemNode id="in111" focusViewId="/health.jsf" action="goHealth"
                  label="Health"/>
        <itemNode id="in112" focusViewId="/dental.jsf" action="goDental"
                  label="Dental"/>
      </itemNode>
      <itemNode id="in12" focusViewId="/pto.jsf" action="goPto"
                label="Paid Time Off">
        <itemNode id="in121" focusViewId="/vacation.jsf"
                  action="goVacation" label="Vacation"/>
        <itemNode id="in122" focusViewId="/sick.jsf" action="goSick"
                  label="Sick Pay"/>
      </itemNode>
    </itemNode>
    <groupNode id="gn2" idref="newEmp" label="Employee Data">
      <itemNode id="in21" focusViewId="/createemp.jsf" action="goCreate"
                label="Create New Employee"/>
      <itemNode id="in22" focusViewId="/viewdata.jsf" action="goView"
                label="View Data"/>
    </groupNode>
  </itemNode>
  <itemNode id="in02" focusViewId="/globalhelp.jsf" action="goHelp"
            label="Help"/>
  <itemNode id="in03" focusViewId="/preferences.jsf" action="goPref"
            label="Preferences"/>
</menu>

Within the root menu element, global nodes are any nodes that are direct children of the menu element. For example, the code in Example 20-5 shows three global nodes, namely, Home, Help, and Preferences.

You can also nest menu models using shared nodes. Use this approach where you have sub trees in the hierarchy (for example, the Benefits tree) as it makes the page hierarchy easier to maintain. For example, you might create the entire Benefits tree as its own menu model metadata file (as shown in Example 20-6) so that the menu model could be reused across an application.

Example 20-6 Benefits XMLMenuModel Metadata File

<?xml version="1.0" encoding="windows-1252" ?>
<menu xmlns="http://myfaces.apache.org/trinidad/menu">
  <itemNode id="in1" focusViewId="/benefits.jsf" action="goBene"
            label="Benefits">
    <itemNode id="in11" focusViewId="/insurance.jsf" action="goIns"
              label="Insurance">
      <itemNode id="in111" focusViewId="/health.jsf" action="goHealth"
                label="Health"/>
      <itemNode id="in112" focusViewId="/dental.jsf" action="goDental"
                label="Dental"/>
    </itemNode>
    <itemNode id="in12" focusViewId="/pto.jsf" action="goPto"
              label="Paid Time Off">
      <itemNode id="in121" focusViewId="/vacation.jsf"
                action="goVacation" label="Vacation"/>
      <itemNode id="in122" focusViewId="/sick.jsf" action="goSick"
                label="Sick Pay"/>
    </itemNode>
  </itemNode>
</menu>

Once you have created the nodes as a separate menu model, then within the different hierarchies that need to use those nodes, you use a shared node to reference the Benefits menu model.

Example 20-7 shows an XMLMenuModel metadata file that uses item nodes, a shared node and a group node to define the same page hierarchy depicted in Figure 20-13.

Example 20-7 XMLMenuModel Metadata File Sample 2

<?xml version="1.0" encoding="windows-1252" ?>
<menu xmlns="http://myfaces.apache.org/trinidad/menu">
  <itemNode id="in01" focusViewId="/home.jsf" label="Home" action="goHome">
    <sharedNode ref="#{benefits_menu}/>
    <groupNode id="gn2" idref="newEmp" label="Employee Data">
      <itemNode id="in21" focusViewId="/createemp.jsf" action="goCreate"
                label="Create New Employee"/>
      <itemNode id="in22" focusViewId="/viewdata.jsf" action="goView"
                label="View Data"/>
    </groupNode>
  </itemNode>
  <itemNode id="in02" focusViewId="/globalhelp.jsf" action="goHelp"
            label="Help"/>
  <itemNode id="in03" focusViewId="/preferences.jsf" action="goPref"
            label="Preferences"/>
</menu>

The sharedNode element references the managed bean that is configured for the Benefits XMLMenuModel metadata file. Whenever you use the Create ADF Menu Model wizard to create a metadata file, JDeveloper automatically adds the managed bean configuration for you.

Before you begin:

It may help to understand how the attributes of navigation components affect functionality. For more information, see Section 20.7, "Using a Menu Model to Create a Page Hierarchy."

You may also find it helpful to understand functionality that can be added using other ADF Faces features. For more information, see Section 20.1.2, "Additional Functionality for Navigation Components."

To create the XMLMenuModel metadata:

  1. In the Applications window, locate the project where you want to create the XMLMenuModel metadata file. Expand the WEB-INF node, right-click faces-config.xml and choose Create ADF Menu Model.

    Note:

    If your application uses ADF Controller, then this menu option will not be available to you. You need to instead use a bounded task flow to create the hierarchy. See the "Creating a Page Hierarchy Using Task Flows" section in Developing Fusion Web Applications with Oracle Application Development Framework.

  2. In the Create ADF Menu Model dialog, enter a file name for the XMLMenuModel metadata file, for example, root_menu.

    Tip:

    If you are using more than one XMLMenuModel metadata file to define the page hierarchy, use the name root_menu only for the topmost (root) metadata file that contains references to the other submenu metadata files.

  3. Enter a directory for the metadata file. By default, JDeveloper saves the XMLMenuModel metadata file in the WEB-INF node of the application.

    When you click OK, JDeveloper displays a blank XMLMenuModel metadata file in the source editor, as shown in Example 20-8.

    Example 20-8 Blank XMLMenuModel Metadata File

    <?xml version="1.0" encoding="windows-1252" ?>
    <menu xmlns="http://myfaces.apache.org/trinidad/menu"></menu>
    

    For information about the managed bean configuration that JDeveloper automatically adds for you in faces-config.xml, see Section 20.7.2, "What Happens When You Use the Create ADF Menu Model Wizard."

  4. Select the menu node in the Structure window and enter the appropriate information in the Properties window.

    Table 20-2 shows the attributes you can specify for the menu element.

    Table 20-2 Menu Element Attributes

    Attribute Description

    resourceBundle

    Optional. This is the resource bundle to use for the labels (visible text) of the navigation items at runtime. For example, org.apache.myfaces.demo.xmlmenuDemo.resource.MenuBundle.

    var

    If using a resource bundle, specify an ID to use to reference the bundle in EL expressions for navigation item labels. For example, #{bundle.somelabel}. See Example 20-9 for a sample XMLMenuModel metadata file that uses a resource bundle.

    xmlns

    Required. Set to http://myfaces.apache.org/trinidad/menu


    Example 20-9 shows sample XMLMenuModel metadata code that uses EL expressions to access a resource bundle for the navigation item labels.

    Example 20-9 XMLMenuModel Using Resource Bundle

    <?xml version="1.0" encoding="windows-1252" ?>
    <menu xmlns="http://myfaces.apache.org/trinidad/menu"
          resourceBundle="org.apache.myfaces.demo.xmlmenuDemo.resource.MenuBundle"
          var="bundle">
      <itemNode id="in1" label="#{bundle.somelabel1}" ../>
      <itemNode id="in2" label="#{bundle.somelabel2}" ../>
    </menu>
    

    Note:

    When you use a sharedNode element to create a submenu and you use resource bundles for the navigation item labels, it is possible that the shared menu model will use the same value for the var attribute on the root menu element. The XMLMenuModel class handles this possibility during parsing by ensuring that each resource bundle is assigned a unique hash key.

    For more information about using resource bundles, see Chapter 32, "Internationalizing and Localizing Pages."

  5. In the Structure window, right-click menu and choose Insert inside menu, and then choose the desired element (itemNode, groupNode, or sharedNode) from the subsequent context menu, as shown in Figure 20-14, to add to the nodes in your hierarchy.

    Figure 20-14 Context Menu for Inserting Elements into Menu

    Context menu for inserting elements into menu

    The elements can be one of the following:

    • itemNode: Specifies a node that performs navigation upon user selection.

    • groupNode: Groups child components; the groupNode itself does no navigation. Child nodes node can be itemNode or another groupNode.

      For example, say you did not need a page for the Employee Data node, but instead, wanted the user to navigate directly to the View Employee page. You would then use a group node to represent the Employee Data page by specifying the id attribute of the desired child node as a value for the group node's idref attribute. The group node allows you to retain the hierarchy without needing to create pages for nodes that are simply aggregates for their children nodes.

    • sharedNode: References another XMLMenuModel instance. A sharedNode element is not a true node; it does not perform navigation nor does it render anything on its own.

      You can insert a sharedNode element anywhere within the hierarchy. For example, in the code shown in Example 20-10, the sharedNode element adds a submenu on the same level as the first-level Employee Data node.

      Example 20-10 SharedNode Sample Code

      <?xml version="1.0" encoding="windows-1252" ?>
      <menu xmlns="http://myfaces.apache.org/trinidad/menu"
        <itemNode id="in0" label="Home" ..>
          <sharedNode ref="#{shared_menu}"/>
          <itemNode id="in1" label="Employee Data" ../>
        </itemNode>
        <itemNode id="in01" label="Help" ../>
      </menu>
      

    As you build the XMLMenuModel metadata file, the tree structure you see in the Structure window exactly mirrors the indentation levels of the menu metadata, as shown in Figure 20-15.

    Figure 20-15 Tree Structure of XMLMenuModel Metadata in Structure Window

    Tree structure in Structure window
  6. For each element used to create a node, set the properties in the Properties window, as described in Table 20-3 for itemNode elements, Table 20-4 for groupNode elements, and Table 20-5 for sharedNode elements.

    Table 20-3 itemNode Element Attributes

    Attribute Description

    action

    Specify either an outcome string or an EL method binding expression that returns an outcome string. In either case, the outcome string must match the from-outcome value to the navigation case for that node as configured in the faces-config.xml file.

    destination

    Specify the URI of the page to navigate to when the node is selected, for example, http://www.oracle.com. If the destination is a JSF page, the URI must begin with "/faces".

    Alternatively, specify an EL method expression that evaluates to the URI.

    If both action and destination are specified, destination takes precedence over action.

    focusViewId

    Required. The URI of the page that matches the node's navigational result, that is, the to-view-id value of the navigation case for that node as specified in the faces-config.xml file.

    For example, if the action outcome of the node navigates to /page_one.jsf (as configured in the faces-config.xml file), then focusViewId must also be /page_one.jsf.

    The focusViewId does not perform navigation. Page navigation is the job of the action or destination attributes. The focusViewId, however, is required for the XMLMenuModel to determine the correct focus path.

    id

    Required. Specify a unique identifier for the node.

    As shown in Example 20-5, it is good practice to use "inX" for the ID of each itemNode, where for example, "inX" could be in1, in11, in111, in2, in21, in 211, and so on.

    label

    Specify the label text to display for the node. Can be an EL expression to a string in a resource bundle, for example, #{bundle.somelabel}, where bundle must match the root menu element's var attribute value.


    A groupNode element does not have the action or destination attribute that performs navigation directly, but it points to a child node that has the action outcome or destination URI, either directly by pointing to an itemNode child (which has the action or destination attribute), or indirectly by pointing to a groupNode child that will then point to one of its child nodes, and so on until an itemNode element is reached. Navigation will then be determined from the action outcome or destination URI of that itemNode element.

    Consider the groupNode code shown in Example 20-11. At runtime, when users click groupNode id="gn1", or groupNode id="gn11", or itemNode id="in1", the navigation outcome is "goToSubTabOne", as specified by the first itemNode reached (that is itemNode id="id1"). Table 20-4 shows the attributes you must specify when you use a groupNode element.

    Example 20-11 groupNode Elements

    <?xml version="1.0" encoding="windows-1252" ?>
    <menu xmlns:"http://myfaces.apache.org/trinidad/menu">
      <groupNode id="gn1" idref="gn11" label="GLOBAL_TAB_0">
        <groupNode id="gn11" idref="in1" label="PRIMARY_TAB_0">
          <itemNode id="in1" label="LEVEL2_TAB_0" action="goToSubTabOne"
                    focusViewId="/menuDemo/subtab1.jsf"/>
          <itemNode id="in2" label="LEVEL2_TAB_1" action="goToSubTabTwo"
                    focusViewId="/menuDemo/subtab2.jsf"/>
        </groupNode>
        <itemNode id="in3" label="PRIMARY_TAB_1" focusViewId="/menuDemo/tab2.jsf"
                  destination="/faces/menuDemo/tab2.jsf"/>
      </groupNode>
      <itemNode id="gin1" label="GLOBAL_TAB_1" action="goToGlobalOne" 
                focusViewId="/menuDemo/global1.jsf"/>
      <itemNode id="gin2" label="GLOBAL_TAB_2" 
                destination="/faces/menuDemo/global2.jsf"
                focusViewId="/menuDemo/global2.jsf"/>
    </menu>
    

    Table 20-4 GroupNode Element Attribute

    Attribute Description

    id

    A unique identifier for the group node.

    As shown in Example 20-11, it is good practice to use gnX for the ID of each groupNode, where for example, gnX could be gn1, gn2, and so on.

    idref

    Specify the ID of a child node, which can be an itemNode, or another groupNode. When adding a groupNode as a child node, that child in turn can reference another groupNode and so on, but eventually an itemNode child must be referenced as the last child.

    The idref attribute can contain more than one child ID, separated by spaces; the IDs are processed in the order they are listed.

    label

    Specify the label text to display for the group node. Can be an EL expression to a string in a resource bundle, for example, #{bundle.somelabel}.


    Table 20-5 sharedNode Element Attribute

    Attribute Description

    ref

    Specify the managed bean name of another XMLMenuModel class, as configured in the faces-config.xml file, for example, #{shared_menu}.

    At runtime, the referenced navigation menu is created, inserted as a submenu into the main (root) menu, and rendered.


20.7.2 What Happens When You Use the Create ADF Menu Model Wizard

When you use the Create ADF Menu Model wizard to create an XMLMenuModel metadata file, JDeveloper automatically configures for you a managed bean for the menu metadata file in the faces-config.xml file, using the metadata file name you provide as the managed bean name.

Example 20-12 shows part of the faces-config.xml file that contains the configuration of one XMLMenuModel metadata file. By default, JDeveloper uses the oracle.adf.view.rich.model.MDSMenuModel class as the managed bean class, and request as the managed bean scope, which is required and cannot be changed.

Example 20-12 Managed Bean Configuration for XMLMenuModel in faces-config.xml

<managed-bean>
  <managed-bean-name>root_menu</managed-bean-name>
  <managed-bean-class>oracle.adf.view.
                      rich.model.MDSMenuModel</managed-bean-class>
  <managed-bean-scope>request</managed-bean-scope>
  <managed-property>
    <property-name>createHiddenNodes</property-name>
    <value>false</value>
  </managed-property>
  <managed-property>
    <property-name>source</property-name>
    <property-class>java.lang.String</property-class>
    <value>/WEB-INF/root_menu.xml</value>
  </managed-property>
</managed-bean>

In addition, the following managed properties are added by JDeveloper for the XMLMenuModel managed bean:

  • createHiddenNodes: When true, specifies that the hierarchical nodes must be created even if the component's rendered attribute is false. The createHiddenNodes value is obtained and made available when the menu metadata source file is opened and parsed. This allows the entire hierarchy to be created, even when you do not want the actual component to be rendered.

  • source: Specifies the menu metadata source file to use (for example, /WEB-INF/root_menu.xml).

Note:

The createHiddenNodes property must be placed before the source property, which JDeveloper does for you when the managed bean is automatically configured. The XMLMenuModel managed bean must have the createHiddenNodes value already set to properly parse and create the menu's XML metadata from the source managed property.

For each XMLMenuModel metadata file that you create in a project using the wizard, JDeveloper configures a managed bean for it in the faces-config.xml file. For example, if you use a sharedNode element in an XMLMenuModel to reference another XMLMenuModel metadata file (as shown in Example 20-10), you would have created two metadata files. And JDeveloper would have added two managed bean configurations in the faces-config.xml file, one for the main (root) menu model, and a second managed bean for the shared (referenced) menu model, as shown in Example 20-13.

Example 20-13 Managed Bean for Shared Menu Model in faces-config.xml

<!-- managed bean for referenced, shared menu model -->
<managed-bean>
  <managed-bean-name>shared_menu</managed-bean-name>
  <managed-bean-class>
  <managed-bean-class>oracle.adf.view.
                      rich.model.MDSMenuModel</managed-bean-class>
  </managed-bean-class>
  <managed-bean-scope>request</managed-bean-scope>
  <managed-property>
    <property-name>createHiddenNodes</property-name>
    <value>false</value>
  </managed-property>
  <managed-property>
    <property-name>source</property-name>
    <property-class>java.lang.String</property-class>
    <value>/WEB-INF/shared_menu.xml</value>
  </managed-property>
</managed-bean>

This means, if you use shared nodes in your XMLMenuModel metadata files, the faces-config.xml file will have a root menu model managed bean, plus menu model managed beans for any menu models referenced through shared nodes.

20.7.3 How to Bind the navigationPane Component to the Menu Model

Each node in the page hierarchy corresponds to one JSF page. On each page, you use one navigationPane component for each level of navigation items that you have defined in your XMLMenuModel metadata file, including global items. Levels are defined by a zero-based index number: Starting with global nodes in the metadata file (that is, direct children nodes under the menu element as shown in Example 20-5), the level attribute value is 0 (zero), followed by 1 for the next level (typically tabs), 2 for the next level after that (typically bars), and so on. For example, if you had a page hierarchy like the one shown in Figure 20-13 and Example 20-5, you would use three navigationPane components on a page such as Home (for the three levels of navigation under the Home node), plus one more navigationPane component for the global nodes.

Tip:

Because the menu model dynamically determines the hierarchy (that is, the links that appear in each navigationPane component) and also sets the current nodes in the focus path as selected, you can practically reuse the same code for each page. You need to change only the page's document title, and add the specific page contents to display on that page.

Because of this similar code, you can create a single page fragment that has just the facets containing the navigationPane components, and include that fragment in each page, where you change the page's document title and add the page contents.

As described in Section 20.8.1, "How to Create a Simple Page Hierarchy," you use the hint attribute to specify the type of navigation item you want to use for each hierarchical level (for example, buttons, tabs, or bar). But instead of manually adding multiple commandNavigationItem components yourself to provide the navigation items, you bind each navigationPane component to the root XMLMenuModel managed bean, and insert only one commandNavigationItem component into the nodeStamp facet of each navigationPane component, as shown in Example 20-14.

Example 20-14 navigationPane Component Bound to XMLMenuModel Managed Bean

<af:navigationPane var="menuNode" value="#{root_menu}" level="0"
                   hint="buttons">
  <f:facet name="nodeStamp">
    <af:commandNavigationItem text="#{menuNode.label}"
                              action="#{menuNode.doAction}"
                              icon="#{menuNode.icon}"
                              destination="#{menuNode.destination}"
                              visible="#{menuNode.visible}"
                              rendered="#{menuNode.rendered}"/>
  </f:facet>
</af:navigationPane>

The nodeStamp facet and its single commandNavigationItem component, in conjunction with the XMLMenuModel managed bean, are responsible for:

  • Stamping out the correct number of navigation items in a level.

  • Displaying the correct label text and other properties as defined in the metadata. For example, the EL expression #{menuNode.label} retrieves the correct label text to use for a navigation item, and #{menuNode.doAction} evaluates to the action outcome defined for the same item.

  • Marking the current items in the focus path as selected. You should not specify the selected attribute at all for the commandNavigationItem components.

Note:

If there is no node information in the XMLMenuModel object for a particular hierarchical level (for example, level 3 lists), ADF Faces does not display those items on the page even though the page contains the navigationPane component code for that level.

If you want the navigation items to be styled, create a decorativeBox component by dragging and dropping a Decorative Box from the Layout panel of the Components window to the JSF page. Set the theme to determine how you want the tabs to appear. Valid values are:

  • default

  • light

  • medium

  • dark

Each value describes the look and feel applied to the application by its ADF skin when you specify the theme value for the component. You can change how the themes display. For more information, see Chapter 31, "Customizing the Appearance Using Styles and Skins."

Before you begin:

It may help to understand how the attributes of navigation components affect functionality. For more information, see Section 20.7, "Using a Menu Model to Create a Page Hierarchy."

You may also find it helpful to understand functionality that can be added using other ADF Faces features. For more information, see Section 20.1.2, "Additional Functionality for Navigation Components."

To bind a navigationPane component to the menu model:

  1. In the Components window, from the Layout panel, in the Interactive Containers and Headers group, drag and drop a Navigation Pane onto the JSF page for each level of the hierarchy.

    For example, to create any of the pages as shown in the hierarchy in Figure 20-13, you drag and drop four navigationPane components onto the JSF page.

  2. For each navigationPane component, in the Properties window, expand the Common section and select one of the following types of navigation items from the Hint dropdown list to determine how the navigationPane displays:

    • bar: Displays the navigation items separated by a bar, for example the Insurance and Paid Time Off links in Figure 20-17.

    • buttons: Displays the navigation items separated by a bar in a global area, for example the Home and Help links in Figure 20-17.

    • choice: Displays the navigation items in a popup list when the associated dropdown icon is clicked. You must include a value for the navigationPane component's icon attribute and you can associate a label to the dropdown list using the title attribute.

    • list: Displays the navigation items in a bulleted list, for example the Health and Dental links in Figure 20-17.

    • tabs: Displays the navigation items as tabs, for example the Benefits and Employee Data tabs in Figure 20-17.

  3. In the Level field, enter a number for the appropriate level of metadata in the XMLMenuModel metadata file. The level attribute is a zero-based index number: Starting with global nodes in the metadata file (that is, direct children nodes under the menu element as shown in Example 20-5), the level attribute value is 0 (zero), followed by 1 for the next level (typically tabs), 2 for the next level after that (typically bars), and so on.

    The commandNavigationItem component is able to get its metadata from the metadata file through the level attribute on the parent navigationPane component. By default, if you do not specify a level attribute value, 0 (zero) is used, that means the navigationPane component will take the metadata from the first level under the menu element for rendering by the commandNavigationItem component.

  4. In the Properties window, expand the Data section and set the following:

    • Value: Set to the menu model managed bean that is configured for the root XMLMenuModel class in the faces-config.xml file.

      Note:

      The value attribute can reference root menu models and menu models referenced by shared nodes. If you reference a shared node in the value attribute, the faces-config.xml file needs to have a new managed bean entry with a different managed bean name than the one which is used in a root menu model definition in the menu model metadata file. This promotes the menu model of a shared node to a root menu model which can then be referred to in the value attribute.

    • Var: Set to text that you will use in the commandNavigationItem components to get the needed data from the menu model.

      As the hierarchy is created at runtime, and each node is stamped, the data for the current node is copied into the var attribute, which can then be addressed using an EL expression. You specify the name to use for this property in the EL expression using the var property.

      Tip:

      You use the same value for the var attribute for every navigationPane component on the page or in the application.

  5. In the Components window, from the Layout panel, in the Interactive Containers and Headers group, drag and drop a Navigation Item to the nodeStamp facet of the navigationPane component.

  6. Set the values for the remaining attributes that have corresponding values in the metadata using EL expressions that refer to the menu model (whose metadata contains that information). You access these values using the value of the var attribute you set for the parent navigationPane component in Step 4 along with the name of the corresponding itemNode element that holds the value in the metadata. Table 20-6 shows the attributes on the navigation item that has corresponding values in the metadata.

    Table 20-6 Navigation Item Attributes and the Associated Menu Model Attributes

    Navigation Item Attribute Associated Menu Model Element Attribute

    text

    label

    action

    doAction

    icon

    icon

    destination

    destination

    visible

    visible

    rendered

    rendered


    For example, if you had set the var attribute on the parent navigationPane component to menuNode, you would use #{menuNode.doAction} as the EL expression for the value of the action attribute. This would resolve to the action property set in the metadata for each node. Example 20-15 shows the JSF code for binding to a menu model that has four levels of hierarchical nodes.

    Example 20-15 Binding to the XMLMenuModel

    <af:form>
      <af:navigationPane hint="buttons" level="0" value="#{root_menu}"
                         var="menuNode">
        <f:facet name="nodeStamp">
          <af:commandNavigationItem text="#{menuNode.label}"
                                    action="#{menuNode.doAction}"
                                    icon="#{menuNode.icon}"
                                    destination="#{menuNode.destination}"/>
        </f:facet>
      </af:navigationPane>
      <af:navigationPane hint="tabs" level="1" value="#{root_menu}"
                         var="menuNode">
        <f:facet name="nodeStamp">
          <af:commandNavigationItem text="#{menuNode.label}"
                                    action="#{menuNode.doAction}"
                                    icon="#{menuNode.icon}"
                                    destination="#{menuNode.destination}"/>
        </f:facet>
      </af:navigationPane>
      <af:navigationPane hint="bar" level="2" value="#{root_menu}"
                         var="menuNode">
        <f:facet name="nodeStamp">
          <af:commandNavigationItem text="#{menuNode.label}"
                                    action="#{menuNode.doAction}"
                                    icon="#{menuNode.icon}"
                                    destination="#{menuNode.destination}"/>
        </f:facet>
      </af:navigationPane>
      <af:navigationPane hint="list" level="3" value="#{root_menu}"
                         var="menuNode">
        <f:facet name="nodeStamp">
          <af:commandNavigationItem text="#{menuNode.label}"
                                    action="#{menuNode.doAction}"
                                    icon="#{menuNode.icon}"
                                    destination="#{menuNode.destination}"/>
        </f:facet>
      </af:navigationPane>
    </af:form>
    

Note:

For information about how to let users close navigation tabs, see Section 20.8.3, "What You May Need to Know About Removing Navigation Tabs."

20.7.4 How to Use the breadCrumbs Component with a Menu Model

Creating a breadcrumb using the menu model is similar to creating the page hierarchy; you use the breadCrumbs component with a nodeStamp facet that stamps a commandNavigationItem component with data from the model.

Before you begin:

It may help to understand how the attributes of navigation components affect functionality. For more information, see Section 20.7, "Using a Menu Model to Create a Page Hierarchy."

You may also find it helpful to understand functionality that can be added using other ADF Faces features. For more information, see Section 20.1.2, "Additional Functionality for Navigation Components."

To create a breadcrumb using a menu model:

  1. In the Components window, from the General Controls panel, in the Location group, drag and drop a BreadCrumbs onto the JSF page.

  2. By default, breadcrumb links display in a horizontal line. To change the layout to be vertical, in the Properties window, expand the Common section and select vertical from the Orientation dropdown list.

  3. In the Properties window, expand the Data section and the set the following:

    • Value: Set to the root XMLMenuModel managed bean as configured in the faces-config.xml file. This is the same bean to which the navigationPane component is bound.

      Note:

      The value attribute should reference only a root menu model and not any menu models referenced through shared nodes. For example, if you use a shared node in your main XMLMenuModel element (as shown in Example 20-10), JDeveloper would have created managed bean configurations for the shared node and the root XMLMenuModel bean that consumes the shared model. The shared model managed bean is automatically incorporated into the root menu model managed bean as the menu tree is parsed at startup.

    • Var: Set to text that you will use in the commandNavigationItem components to get the needed data from the menu model.

      As the hierarchy is created at runtime, and each node is stamped, the data for the current node is copied into the var attribute, which can then be addressed using an EL expression. You specify the name to use for this property in the EL expression using the var property.

      Tip:

      You can use the same value for the var attribute for the breadCrumbs component as you did for the navigationPane components on the page or in the application.

  4. In the Components window, from the Layout panel, in the Interactive Containers and Headers group, drag a Navigation Item and drop it inside the nodeStamp facet of the breadCrumbs component.

    Note:

    The nodeStamp facet of the breadCrumbs component determines what links appear according to the menu model that you specify for the value attribute of the breadCrumbs component. If you do not specify the menu model you want to render for the value attribute of the breadCrumbs component, no links appear at runtime. Do not use a nodeStamp facet for the breadCrumbs component if you do not use a menu model because no stamps will be required.

  5. Set the values for the remaining attributes that have corresponding values in the metadata using EL expressions that refer to the menu model (whose metadata contains that information). You access these values using the value of the var attribute you set for the parent breadCrumbs component in Step 3 along with the name of the corresponding itemNode element that holds the value in the metadata. Table 20-6 shows the attributes on the navigation item that has corresponding values in the metadata.

    For example, if you had set the var attribute on the breadCrumbs component to menuNode, you would use #{menuNode.doAction} as the EL expression for the value of the action attribute. This would resolve to the action property set in the metadata for each node.

    Example 20-16 breadCrumbs Component Bound to the XMLMenuModel

    <af:breadCrumbs var="menuNode" value="#{root_menu}">
      <f:facet name="nodeStamp">
        <af:commandNavigationItem text="#{menuNode.label}"
                                  action="#{menuNode.doAction}"/>
      </f:facet>
    </af:breadCrumbs>
    

20.7.5 How to Use the menuBar Component with a Menu Model

As described in Chapter 16, "Using Menus, Toolbars, and Toolboxes," the menuBar and menu components are usually used to organize and create menus that users click to cause some change or action in the application. Where applicable, the menuBar component can be used with an XMLMenuModel implementation and managed beans to create a page hierarchy. Like the breadCrumbs or navigationPane component, when menuBar is bound to the root XMLMenuModel managed bean, you use one commandNavigationItem component in the nodeStamp facet to dynamically provide the menu items for navigating the page hierarchy.

When the page hierarchy of a website cannot be sufficiently represented by a tabbed navigation system (through a navigationPane or panelTabbed component), use the menuBar component to provide a navigation bar of menus and submenus. For example, a web store application with many shopping categories for users to browse might benefit from a horizontal arrangement of top-level menus in a bar instead of rendering all the categories and subcategories within tabs, subtabs or bars, and lists. With a menuBar bound to a menu model, submenus appear only when the user places the mouse cursor over a top-level menu or a submenu item. Not only does this arrangement reduce screen real estate, but the user can also quickly navigate from the top of the hierarchy to a page at the lowest level with just one click.

Unlike a menuBar component that is not bound to a menu model, a menuBar that is bound to a menu model is not detachable, and should not be used with a toolbar. Also, do not use navigation tabs with a menuBar bound to a menu model on the same page. If you must use both, always place the menuBar component above the navigation tabs. You can, however, use a menuBar bound to a menu model with a breadCrumbs component bound to the same model on those pages where you want to show breadcrumb links.

If you want the menu bar to be styled, create a decorativeBox component by dragging and dropping a Decorative Box from the Layout panel of the Components window to the JSF page. Set the theme to determine how you want the tabs to appear. Valid values are:

  • default

  • light

  • medium

  • dark

Each value describes the look and feel applied to the application by its ADF skin when you specify the theme value for the component. You can change how the themes display. For more information, see Chapter 31, "Customizing the Appearance Using Styles and Skins."

Before you begin:

It may help to understand how the attributes of navigation components affect functionality. For more information, see Section 20.7, "Using a Menu Model to Create a Page Hierarchy."

You may also find it helpful to understand functionality that can be added using other ADF Faces features. For more information, see Section 20.1.2, "Additional Functionality for Navigation Components."

To create a horizontal menu bar using a menu model:

  1. In the Components window, from the Menus and Toolbars panel, drag and drop a Menu Bar onto the JSF page.

  2. In the Properties window, expand the Menu Model section and set the following values:

    • Value: Set to the root XMLMenuModel managed bean as configured in the faces-config.xml file. This is the same bean to which the breadCrumbs component is bound.

      Note:

      The value attribute should reference only a root menu model and not any menu models referenced through shared nodes. For example, if you use a shared node in your main XMLMenuModel element (as shown in Example 20-10), JDeveloper would have created managed bean configurations for the shared node and the root XMLMenuModel bean that consumes the shared model. The shared model managed bean is automatically incorporated into the root menu model managed bean as the menu tree is parsed at startup.

    • Var: Set to the text that you will use in the commandNavigationItem components to get the needed data from the menu model.

      As the hierarchy is created at runtime, and each node is stamped, the data for the current node is copied into the var attribute, which can then be addressed using an EL expression. You specify the name to use for this property in the EL expression using the var property.

      Tip:

      You can use the same value for the var attribute for the menuBar component as you did for the breadCrumbs component on the page or in the application.

  3. In the Components window, from the Layout panel, in the Interactive Containers and Headers group, drag and drop a Navigation Item to the nodeStamp facet of the menuBar component.

    Note:

    The nodeStamp facet of the menuBar component determines what links appear according to the menu model that you specify for the value attribute of the menuBar component. If you do not specify the menu model you want to render for the value attribute of the menuBar component, no menu items will appear at runtime.

  4. Set the values for the remaining attributes that have corresponding values in the metadata using EL expressions that refer to the menu model (whose metadata contains that information). You access these values using the value of the var attribute you set for the parent menuBar component in Step 2 along with the name of the corresponding itemNode element that holds the value in the metadata. Table 20-6 shows the attributes on the navigation item that has corresponding values in the metadata.

    For example, if you had set the var attribute on the menuBar component to menuNode, you would use #{menuNode.doAction} as the EL expression for the value of the action attribute. This would resolve to the action property set in the metadata for each node.

    Example 20-17 menuBar Component Bound to the XMLMenuModel

    <af:menuBar var="menuNode" value="#{root_menu}">
      <f:facet name="nodeStamp">
        <af:commandNavigationItem text="#{menuNode.label}"
                                  action="#{menuNode.doAction}"/>
      </f:facet>
    </af:menuBar>
    

20.7.6 What Happens at Runtime: How the Menu Model Creates a Page Hierarchy

The value attribute of the menu model bound component (navigationPane, breadCrumbs, or menuBar) references the managed bean for the XMLMenuModel element. When that managed bean is requested, the following takes place:

  • The setSource() method of the XMLMenuModel class is called with the location of the model's metadata, as specified in the managed-property element in the faces-config.xml file.

  • An InputStream object to the metadata is made available to the parser (SAXParser); the metadata for the navigation items is parsed, and a call to MenuContentHandler method is made.

  • The MenuContentHandler builds the navigation menu tree structure as a List object in the following manner:

    • The startElement() method is called at the start of processing a node in the metadata.

    • The endElement() method is called at the end of processing the node.

    • As each node is processed, a List of navigation menu nodes that make up the page hierarchy of the menu model is created.

  • A TreeModel object is created from the list of navigation menu nodes.

  • The XMLMenuModel object is created from the TreeModel object.

If a groupNode element has more than one child id in its idref attribute, the following occurs:

  • The IDs are processed in the order they are listed. If no child node is found with the current ID, the next ID is used, and so on.

  • Once a child node is found that matches the current ID in the idref list, then that node is checked to see if its rendered attribute is set to true, its disabled attribute is set to false, its readOnly attribute is set to false, and its visible attribute is set to true. If any of the criteria is not met, the next ID in the idref list is used, and so on.

  • The first child node that matches the criteria is used to obtain the action outcome or destination URI. If no child nodes are found that match the criteria, an error is logged. However, no error will be shown in the UI.

  • If the first child node that matches the criteria is another groupNode element, the processing continues into its children. The processing stops when an itemNode element that has either an action or destination attribute is encountered.

  • When the itemNode element has an action attribute, the user selection initiates a POST action and the navigation is performed through the action outcome. When the itemNode element has a destination attribute, the user selection initiates a GET action and navigation is performed directly using the destination value.

The XMLMenuModel class provides the model that correctly highlights and enables the items on the navigation menus (such as tabs and bars) as you navigate through the navigation menu system. The model is also instantiated with values for label, doAction, and other properties that are used to dynamically generate the navigation items.

The XMLMenuModel class does no rendering; the model bound component uses the return value from the call to the getFocusRowKey() method to render the navigation menu items for a level on a page.

The commandNavigationItem component housed within the nodeStamp facet of the menu model bound component provides the label text and action outcome for each navigation item. Each time the nodeStamp facet is stamped, the data for the current navigation item is copied into an EL-reachable property, the name of which is defined by the var attribute on the navigationPane component that houses the nodeStamp facet. The nodeStamp displays the data for each item by getting further properties from the EL-reachable property. Once the navigation menu has completed rendering, this property is removed (or reverted back to its previous value). When users select a navigation item, the default JSF actionListener mechanism uses the action outcome string or destination URI to handle the page navigation.

The XMLMenuModel class, in conjunction with nodeStamp facet also controls whether or not a navigation item is rendered as selected. As described earlier, the XMLMenuModel object is created from a tree model, which contains viewId attribute information for each node. The XMLMenuModel class has a method getFocusRowKey() that determines which page has focus, and automatically renders a node as selected if the node is on the focus path. The getFocusRowKey() method in its most simplistic fashion does the following:

  • Gets the current viewId attribute.

  • Compares the viewId attribute value with the IDs in internal maps used to resolve duplicate viewId values and in the viewIdFocusPathMap object that was built by traversing the tree when the menu model was created.

  • Returns the focus path to the node with the current viewId attribute or returns null if the current viewId attribute value cannot be found.

The viewId attribute of a node is used to determine the focus rowKey object. Each item in the model is stamped based on the current rowKey object. As the user navigates and the current viewId attribute changes, the focus path of the model also changes and a new set of navigation items is accessed.

20.7.7 What You May Need to Know About Using Custom Attributes

Custom attributes that you have created can be displayed, but only for itemNode elements. To add an itemNode element to access the value of a custom attribute, you need to get the tree from the menu model by:

  • Calling the menu models getWrappedData() method

  • Calling the getFocusRowKey() method to get the current focus path

  • Using this focus path to traverse the tree and return a list of nodes in the focus path

  • Testing one or more of these nodes for custom attribute(s) by calling the getCustomProperty() API

Example 20-18 shows an example of the required code.

Example 20-18 Accessing Custom Attributes from the XMLMenuModel

/**
    * Returns the nodes corresponding to a focus path
    * 
    * @param tree
    * @param focusPath
    */
    public List getNodesFromFocusPath(TreeModel tree, ArrayList focusPath)
    {
      if (focusPath == null || focusPath.size() == 0)
        return null;
 
      // Clone the focusPath cause we remove elements
      ArrayList fp = (ArrayList) focusPath.clone();
  
      // List of nodes to return
      List nodeList = new ArrayList<Object>(fp.size());
  
      // Convert String rowkey to int and point to the
      // node (row) corresponding to this index
      int targetNodeIdx = Integer.parseInt((String)fp.get(0));
      tree.setRowIndex(targetNodeIdx);
 
      // Get the node
      Object node = tree.getRowData()
 
      // put the Node in the List
      nodeList.add(node);
 
      // Remove the 0th rowkey from the focus path
      // leaving the remaining focus path
      fp.remove(0);
  
      // traverse into children 
      if (   fp.size() > 0
          && tree.isContainer() 
          && !tree.isContainerEmpty()
         )
      {
        tree.enterContainer();
  
        // get list of nodes in remaining focusPath
        List childList = getNodesFromFocusPath(tree, fp);
  
        // Add this list to the nodeList
        nodeList.addAll(childList);
  
        tree.exitContainer();
      }
  
      return nodeList;
    } 
 
  public String getElementLabel(XMLMenuModel model, Object myVal, String myProp)
  {
     TreeModel tree = model.getWrappedData();
     
     Object node = findNodeByPropertyValue(tree, myVal, myProp);
 
     FacesContext context = FacesContext.getCurrentInstance();
     PropertyResolver resolver = context.getApplication().getPropertyResolver();
     
     String label = (String) resolver.getValue(node, _LABEL_ATTR);
     
     return label;
  }
 
  public Object findNodeByPropertyValue(TreeModel tree, Object myVal, String myProp)
  {
    FacesContext context = FacesContext.getCurrentInstance();
    PropertyResolver resolver = context.getApplication().getPropertyResolver();
    
    for ( int i = 0; i < tree.getRowCount(); i++)
    {
      tree.setRowIndex(i);
 
      // Get a node
      Object node = tree.getRowData();
      
      // Get the value of the attribute of the node
      Obect propVal = resolver.getValue(node, myProp);
      
      if (propVal == myVal)
      { 
        return node;
      }        
      
      if (tree.isContainer() && !tree.isContainerEmpty())
      {
        tree.enterContainer();
        node = findNodeByPropertyValue(tree, myVal, myProp);
 
        if (node != null)
          return node;
 
        tree.exitContainer();
      }guap
    }
    return null;
  }  

20.8 Creating a Simple Navigational Hierarchy

Note:

If the application hierarchy is complex and consists of deeply nested pages, it is more efficient to use a menu model to create your navigation system. For details, see Section 20.7, "Using a Menu Model to Create a Page Hierarchy".

Section 20.6, "Using Navigation Items for a Page Hierarchy" describes a simple page hierarchy with three levels of links under a top-level root node, Home. Figure 20-16 and Figure 20-17 show an example of what the user interface could look like when the navigationPane component and individual commandNavigationItem components are used to create a view for the page hierarchy shown in Figure 20-10.

Figure 20-16 Navigation Items Available from the View Employee Page

Navigation items using NavigationPane

When you create the hierarchy manually, first determine the focus path of each page (that is, where exactly in the hierarchy the page resides) in order to determine the exact number of navigationPane and commandNavigationItem components needed for each page, as well as to determine the components that should be configured as selected when the user visits the page. For example, in Figure 20-16, which shows the View Employee page, you would need three navigationPane components. In addition to the first-level tabs, only the second-level child bars of Employee Data are needed, and only the Employee Data tab and View Employee bar render as selected.

Similarly in Figure 20-17, which shows the Health page, only the child bars of Benefits are needed, and the Benefits tab and Insurance bar must be configured as selected. Additionally for this page, you would create the child nodes under Insurance, which can be presented as a vertical list on the side of the page. The Health item in the vertical list is configured as selected, and the contents of the Health page are displayed in the middle, to the right of the vertical list.

Figure 20-17 Navigation Items Available from the Health Page

Navigation items using NavigationPane

Regardless of the type of navigation items you use (such as tabs, bars or lists), you use a navigationPane component to represent one level of hierarchical links, and a series of commandNavigationItem child components within each navigationPane component to provide the actual navigation items. For example, in Figure 20-17 the actual links for the first-level tabs (Benefits and Employee Data), the second-level bars (Insurance and Paid Time Off), and the Health and Dental links in the list are each provided by a commandNavigationItem component. Underneath the bars, to provide the breadcrumb links that show the focus path of the current page, you use a breadCrumbs component with the required number of child commandNavigationItem components.

20.8.1 How to Create a Simple Page Hierarchy

When your navigational hierarchy contains only a few pages and is not very deep, you can choose to manually create the hierarchy. Doing so involves creating the navigation rule and navigation cases, using the navigationPane component to create the hierarchy, and using the commandNavigationItem component to create the links.

Before you begin:

It may help to understand how the attributes of navigation components affect functionality. For more information, see Section 20.8, "Creating a Simple Navigational Hierarchy."

You may also find it helpful to understand functionality that can be added using other ADF Faces features. For more information, see Section 20.1.2, "Additional Functionality for Navigation Components."

To manually create a navigation hierarchy:

  1. In the Applications window, expand the WEB-INF node and double-click faces-config.xml.

  2. In the source editor, create one global JSF navigation rule that has the navigation cases for all the nodes (that is, pages) in the page hierarchy.

    For example, the page hierarchy shown in Figure 20-10 has 10 nodes, including the global Help node. Thus, you would create 10 navigation cases within one global navigation rule in the faces-config.xml file, as shown in Example 20-19.

    For each navigation case, specify a unique outcome string, and the path to the JSF page that should be displayed when the navigation system returns an outcome value that matches the specified string.

    Example 20-19 Global Navigation Rule for a Page Hierarchy in faces-config.xml

    <navigation-rule>
      <navigation-case>
        <from-outcome>goHome</from-outcome>
        <to-view-id>/home.jsf</to-view-id>
      </navigation-case>
      <navigation-case>
        <from-outcome>goHelp</from-outcome>
        <to-view-id>/globalhelp.jsf</to-view-id>
      </navigation-case>
      <navigation-case>
        <from-outcome>goEmp</from-outcome>
        <to-view-id>/empdata.jsf</to-view-id>
      </navigation-case>
      <navigation-case>
        <from-outcome>goBene</from-outcome>
        <to-view-id>/benefits.jsf</to-view-id>
      </navigation-case>
      <navigation-case>
        <from-outcome>goIns</from-outcome>
        <to-view-id>/insurance.jsf</to-view-id>
      </navigation-case>
      <navigation-case>
        <from-outcome>goPto</from-outcome>
        <to-view-id>/pto.jsf</to-view-id>
      </navigation-case>
      <navigation-case>
        <from-outcome>goView</from-outcome>
        <to-view-id>/viewdata.jsf</to-view-id>
      </navigation-case>
      <navigation-case>
        <from-outcome>goCreate</from-outcome>
        <to-view-id>/createemp.jsf</to-view-id>
      </navigation-case>
      <navigation-case>
        <from-outcome>goHealth</from-outcome>
        <to-view-id>/health.jsf</to-view-id>
      </navigation-case>
      <navigation-case>
        <from-outcome>goDental</from-outcome>
        <to-view-id>/dental.jsf</to-view-id>
      </navigation-case>
    </navigation-rule>
    

    For more information about creating navigation cases in JDeveloper, see Section 3.3, "Defining Page Flows."

  3. Create the JSF pages for all the hierarchical nodes. If you want the navigation tabs to be styled, create a decorativeBox component by dragging and dropping a Decorative Box from the Layout panel of the Components window to each page. Set the theme to determine how you want the tabs to appear. Valid values are:

    • default

    • light

    • medium

    • dark

    Each value describes the look and feel applied to the application by its ADF skin when you specify the theme value for the component. You can change how the themes display. For more information, see Chapter 31, "Customizing the Appearance Using Styles and Skins." To consider using a page template to achieve the positioning and visual styling of your JSF pages, see Section 10.3, "Using Page Templates."

  4. In the Components window, from the Layout panel, in the Interactive Containers and Headers group, drag and drop a Navigation Pane to each page. Drag and drop a navigationPane component for each level of the hierarchy on the page.

    For example, to create the Health page, as shown in Figure 20-17, drag and drop four navigationPane components. In the Health page, the components are dropped into specific areas of a template that already contains layout components to create the look and feel of the page.

  5. For each navigationPane component, in the Properties window, expand the Common section and select one of the following types of navigation items from the Hint dropdown list to determine how the navigationPane component displays:

    • bar: Displays the navigation items separated by a bar, for example the Insurance and Paid Time Off links in Figure 20-17.

    • buttons: Displays the navigation items separated by a bar in a global area, for example the Home and Help links in Figure 20-17.

    • choice: Displays the navigation items in a popup list when the associated dropdown icon is clicked. You must include a value for the navigationPane component's icon attribute and you can associate a label to the dropdown list using title attribute.

    • list: Displays the navigation items in a bulleted list, for example the Health and Dental links in Figure 20-17.

    • tabs: Displays the navigation items as tabs, for example the Benefits and Employee Data tabs in Figure 20-17.

  6. For each navigationPane component, add the needed commandNavigationItem components to represent the different links by dragging and dropping a Navigation Item from the Interactive Containers and Headers group in the Layout panel of the Components window. Drop a Navigation Item as a child to the navigationPane component for each link needed.

    For example, to create the Health page as shown in Figure 20-17, you would use a total of eight commandNavigationItem components, two for each navigationPane component.

    Performance Tip:

    At runtime, when available browser space is less than the space needed to display the contents in a tab or bar of a navigation pane, or the contents of the breadcrumb, ADF Faces automatically displays overflow icons that enable users to select and navigate to those items that are out of view. The number of child components within a navigationPane or breadCrumbs component, and the complexity of the children, will affect the performance of the items within the overflow. You should set the size of the navigationPane or breadCrumbs component to avoid overflow when possible.

  7. For each commandNavigationItem component, set the navigation to the desired page. In the Properties window, expand the Common section and provide a static string outcome of an action or use an EL expression to reference an action method in the Action field. If you use a string, it must match the navigation metadata set up in the navigation rules for the page created in Step 2. If referencing a method, that method must return the required string.

  8. In the Properties window, expand the Behavior section and select true from the Selected dropdown list if the commandNavigationItem component should be displayed as selected when the page is first rendered, and false if it should not.

    At runtime, when a navigation item is selected by the user, that component's selected attribute changes to selected="true" and the appearance changes to indicate to the user that the item has been selected. For example, in Figure 20-17 the Benefits tab, Insurance bar, and Health list item are shown as selected by a change in either background color or font style. You do not have to write any code to show the selected status; the selected attribute on the commandNavigationItem component for that item takes care of turning on the selected status when the attribute value is true.

Example 20-20 shows code used to generate the navigation items that are available when the current page is Health. Because the Health page is accessed from the Insurance page from the Benefits page, the commandNavigationItem components for those three links have selected="true".

Example 20-20 Sample Code Using Individual Navigation Items on One Page

<af:navigationPane hint="buttons">
  <af:commandNavigationItem text="Home" action="goHome"/>
  <af:commandNavigationItem text="Help" action="goHelp"/>
</af:navigationPane>
...
<af:navigationPane hint="tabs">
  <af:commandNavigationItem text="Benefits" action="goBene"
                            selected="true"/>
  <af:commandNavigationItem text="Employee Data" action="goEmp"/>
</af:navigationPane>
...
<af:navigationPane hint="bar">
  <af:commandNavigationItem text="Insurance" action="goIns"
                            selected="true"/>
  <af:commandNavigationItem text="Paid Time Off" action="goPto"/>
</af:navigationPane>
...
<af:navigationPane hint="list">
  <af:commandNavigationItem text="Health" action="goHealth"
                            selected="true"/>
  <af:commandNavigationItem text="Dental" action="goDental"/>
</af:navigationPane>

To change the selected state programmatically, you have to write a backing bean method to handle an action event. Then reference the method on the actionListener attribute of the commandNavigationItem components, as shown in Example 20-21.

Example 20-21 Using actionListener to Change Selected State

<!--  JSF Page Code ----->
<af:navigationPane hint="tabs">
  <af:commandNavigationItem text="Benefits"
                            actionListener="#{myBean.navigationItemAction}"
                            partialSubmit="true"../>
  .
</af:navigationPane>

<!-- Managed Bean Code ----->
public void navigationItemAction(ActionEvent event)
{
  UIComponent actionItem = event.getComponent();
  UIComponent parent = actionItem.getParent();
  while (! (parent instanceof UIXNavigationHierarchy) )
  {
    parent = parent.getParent();
    if (parent == null)
    {
      System.err.println(
       "Unexpected component hierarchy, no UIXNavigationHierarchy found.");
      return;
    }
  }

  List<UIComponent> children = parent.getChildren();
  for (UIComponent child : children)
  {
    FacesBean childFacesBean = ((UIXComponent) child).getFacesBean();
    FacesBean.Type type = childFacesBean.getType();
    PropertyKey selectedKey = type.findKey("selected");
    if (selectedKey != null)
    {
      childFacesBean.setProperty(selectedKey, child==actionItem);
    }
  }
  RequestContext adfContext = RequestContext.getCurrentInstance();
  adfContext.addPartialTarget(parent);
}

20.8.2 How to Use the breadCrumbs Component

In both Figure 20-16 and Figure 20-17, the user's current position in the page hierarchy is indicated by a path of links from the current page back to the root page. The path of links, also known as breadcrumbs, is displayed beneath the secondary bars, above the vertical lists (if any). To manually create such a path of links, you use the breadCrumbs component with a series of commandNavigationItem components as children.

Before you begin:

It may help to understand how the attributes of navigation components affect functionality. For more information, see Section 20.8, "Creating a Simple Navigational Hierarchy."

You may also find it helpful to understand functionality that can be added using other ADF Faces features. For more information, see Section 20.1.2, "Additional Functionality for Navigation Components."

To manually create a breadcrumb:

  1. In the Components window, from the General Controls panel, in the Location group, drag and drop a BreadCrumbs onto the JSF page.

  2. By default, breadcrumb links are displayed in a horizontal line. To change the layout to be vertical, in the Properties window, expand the Common section and select vertical from the Orientation dropdown list.

  3. For each link in the breadcrumb, create a commandNavigationItem component by dragging and dropping a Navigation Item from the Interactive Containers and Headers group in the Layout panel of the Components window as a child to the breadCrumbs component. The last item should represent the current page.

    Tip:

    Depending on the renderer or client device type, the last link in the breadcrumb may not be displayed, but you still must add the commandNavigationItem component for it. On clients that do display the last breadcrumb link, the link is always disabled automatically because it corresponds to the current page.

  4. For each commandNavigationItem component (except the last), set the navigation to the desired page. In the Properties window, expand the Common section and provide a static string outcome of an action or use an EL expression to reference an action method in the Action field. If you use a string, it must match the navigation metadata set up in the navigation rule for the page created in Step 2 as described in Section 20.8.1, "How to Create a Simple Page Hierarchy." If referencing a method, that method must return the required string.

For example, to create the breadcrumb as shown on the Health page in Figure 20-17, drag and drop four commandNavigationItem components, as shown in Example 20-22.

Example 20-22 BreadCrumbs Component With Individual CommandNavigationItem Children

<af:breadCrumbs>
  <af:commandNavigationItem text="Home" action="goHome"/>
  <af:commandNavigationItem text="Benefits" action="goBene"/>
  <af:commandNavigationItem text="Insurance" action="goIns"/>
  <af:commandNavigationItem text="Health"/>
</af:breadCrumbs>

20.8.3 What You May Need to Know About Removing Navigation Tabs

You can configure a navigationPane component whose hint attribute value is tabs so that the individual tabs can be closed. You can set it such that all tabs can be closed, all but the last tab can be closed, or no tabs can be closed. When navigation tabs are configured to be removed, a close icon (for example, an X) displays at the end of each tab as the mouse cursor hovers over the tab.

To enable tabs removal in a navigationPane component when hint="tabs", you need to do the following:

  • Set the itemRemoval attribute on navigationPane hint="tabs" to all or allExceptLast. When set to allExceptLast, all but one tab can be closed. This means as a user closes tabs, when there is only one tab left, that single last tab cannot be closed.

  • Implement a handler to do the tab removal. When a user closes a tab, an ItemEvent of type remove is launched. Your code must handle this event and the actual removal of the tab, and any other desired functionality (for example, show a warning dialog on how to handle child components). For more information about events, see Chapter 6, "Handling Events." For information about using popup dialogs and windows, see Chapter 15, "Using Popup Dialogs, Menus, and Windows."

  • Set the itemListener attribute on the commandNavigationItem component to an EL expression that resolves to the handler method that handles the actual tab removal, as shown in Example 20-23.

Example 20-23 Using itemListener to Remove a Tab Item

<!---- JSF Page Code ----->
<af:navigationPane hint="tabs" itemRemoval="all">
  <af:commandNavigationItem text="Benefits" partialSubmit="true"
                            itemListener="#{closebean.handleCloseTabItem}"/>
  ...
</af:navigationPane>

// Managed Bean Code 
import oracle.adf.view.rich.event.ItemEvent;
...
public void handleCloseTabItem(ItemEvent itemEvent)
{
  if (itemEvent.getType().equals(ItemEvent.Type.remove))
  {
    Object item = itemEvent.getSource();
    if (item instanceof RichCommandNavigationItem)
    {
      RichCommandNavigationItem tabItem = (RichCommandNavigationItem) item;
      tabItem.setVisible(false);
      // do other desired functionality here ...
    }
  }
}

20.8.4 What You May Need to Know About the Size of Navigation Tabs

By default, the size of the tabs rendered by a navigationPane component that has its hint attribute value set to tabs is determined by the length of the text used as the label. You can configure the size of these tabs by configuring the following attributes for the navigationPane component:

  • maxTabSize: Set to a size in pixels. The tabs will never be larger than this size.

  • minTabSize: Set to a size in pixels. The tabs will never be smaller than this size.

  • truncationStyle: Set to ellipsis if you want an ellipses to display after truncated text that cannot fit, based on the maxTabSize. If set to none, then if the text does not fit on the tab, it will simply be truncated.

20.8.5 What You May Need to Know About Navigation Tabs in a Compressed Layout

Built-in overflow indicators appear if the application window is in a compressed layout. That is, the application window is not wide enough to display all the navigation items. These overflow indicators render dropdown lists where the user can choose the navigation item to navigate to, as shown in Figure 20-18.

Figure 20-18 Overflow Indicator for a navigationPane Component in Compressed Layout

Overflow Indicator

Rather than display overflow indicators (the default behavior), as shown in Figure 20-18, you can configure the -tr-layout-type skinning key for the navigationPane component so that the component renders a conveyor belt where users can scroll left or right to items that are not currently visible. Configuring the -tr-layout-type skinning key also renders all navigation items in one dropdown list, as shown in Figure 20-19. This configuration only takes effect if the navigationPane component's hint attribute is set to tabs. If the navigationPane component's hint attribute is set to another value, set the -tr-layout-type skinning key to its default value (overflow).

Example 20-24 shows how you configure the -tr-layout-type skinning key in your application's ADF skin file to render a conveyor belt for the navigationPane and panelTabbed components. For more information about skinning, see Chapter 31, "Customizing the Appearance Using Styles and Skins."

Example 20-24 Configuring the -tr-layout-type Skinning Key to Render a Conveyor Belt

af|panelTabbed,
af|navigationPane {
  -tr-layout-type: conveyor;
}  

Figure 20-19 shows the navigationPane component rendering a conveyor belt in a compressed layout.

Figure 20-19 Conveyor Belt for a navigationPane Component in Compressed Layout

Conveyor Belt navigationPane Component Compressed Layout

20.9 Using Train Components to Create Navigation Items for a Multistep Process

Note:

If your application uses the Fusion technology stack or ADF Controller, then you should use ADF task flows to create the navigation system for your application page hierarchy. For details, see the "Using Train Components in Bounded Task Flows" section in Developing Fusion Web Applications with Oracle Application Development Framework.

If you have a set of pages that users should visit in a particular order, consider using the train component on each page to display a series of navigation items that guide users through the multistep process. Figure 20-20 shows an example of what a rendered train component looks like on a page. Not only does a train component display the number of steps in a multistep process, it also indicates the location of the current step in relation to the entire process.

Figure 20-20 Navigation Items Rendered by a train Component

Navigation Items Rendered by a train Component

The train component renders each configured step represented as a train stop, and with all the stops connected by lines. Each train stop has an image (for example, a square block) with a label underneath the image.

Each train stop corresponds to one step or one page in your multistep process. Users navigate the train stops by clicking an image or label, which causes a new page to display. Typically, train stops must be visited in sequence, that is, a user must start at Step 1, move to Step 2, then Step 3, and so on; a user cannot jump to Step 3 if the user has not visited Step 2. Train stops can also be configured so that end users do not have to visit the stops in sequence. When you configure train stops in this way, all train stops that can be directly visited are enabled.

As shown in Figure 20-20, the train component provides at least four styles for train stops. The current stop where the user is visiting is indicated by a bold font style in the train stop's label, and a different image for the stop; visited stops before the current stop are indicated by a different label font color and image color; the next stop immediately after the current stop appears enabled; any other stops that have not been visited are grayed-out.

A train stop can include a subtrain, that is, you configure an action component (for example, a button component) to start a child multistep process from a parent stop, and then return to the correct parent stop after completing the subprocess. Suppose stop number 3 has a subprocess train containing two stops, when the user navigates into the first stop in the subprocess train, ADF Faces displays an icon representation of the parent train before and after the subprocess train, as shown in Figure 20-21.

Figure 20-21 Parent Train Icons At Start and End of a Subtrain

Subtrain multi-step process

You can use the trainButtonBar component in conjunction with the train component to provide additional navigation items for the train, in the form of Back and Next buttons, as shown in Figure 20-22. These Back and Next buttons allow users to navigate only to the next or previous train stop from the current stop. You can also use the trainButtonBar component without a train component. For example, you may want to display just the Back and Next buttons without displaying the stops when not all of the stops will be visited based on some conditional logic.

Figure 20-22 Navigation Buttons Rendered by a trainButtonBar Component

Back and Next buttons rendered by TrainButtonBar

Both train components work by having the value attribute bound to a train model of type org.apache.myfaces.trinidad.model.MenuModel. The train menu model contains the information needed to:

  • Control a specific train behavior (that is, how the train advances users through the train stops to complete the multistep process).

  • Dynamically generate the train stops, including the train stop labels, and the status of each stop (that is, whether a stop is currently selected, visited, unvisited, or disabled).

Note:

In an application that uses the ADF Model layer and ADF Controller, this navigation and display is set up and handled in a different manner. For more information, see the "Using Train Components in Bounded Task Flows" section in Developing Fusion Web Applications with Oracle Application Development Framework.

Briefly, a menu model for the train is implemented by extending the MenuModel abstract class, which in turn extends the TreeModel class (For more information, see Chapter 12, "Using Tables, Trees, and Other Collection-Based Components"). A MenuModel object represents the menu structure of a page or application or could represent the hierarchy of pages and stops involved in a flow.

Because an instance of a MenuModel class is a special kind of a TreeModel object, the nodes in the TreeModel object can represent the stops of a train. The node instance that represents a train stop within the train component can be of type TrainStopModel, or it can be any object as long as it provides the same EL structure as a TrainStopModel object. However, the TrainStopModel class is a convenient interface that exposes all the relevant methods to retrieve the outcome, as well as the label of a stop and its immediate, disabled, and visited attribute states.

The MenuModel class can also indicate where in the tree the current train stop (page) is focused. The getFocusRowKey() method in the MenuModel class returns the rowKey object of the focus page for the current viewId. The menu model implementation for the train must also have a specific train behavior. You can implement this behavior by extending the MenuModel abstract class or the ProcessMenuModel convenience class. Both these classes come from the following package:

org.apache.myfaces.trinidad.model

The train behavior controls what other stops along the train users can visit while visiting the current train stop.

To create a train stop model, you can either extend the TrainStopModel abstract class and implement the abstract methods, or you can create your own class with the same method signatures. Your class must return a rowData object. An instance of this class represents a rowData object in the underlying collection (for the MenuModel implementation).

Binding a train component to a menu model is similar to binding a navigationPane component to an XMLMenuModel class using the value attribute (described in Section 20.7.3, "How to Bind the navigationPane Component to the Menu Model"). However, as long as your TrainStopModel implementation represents a rowData object, you do not need to use the nodeStamp facet and its commandNavigationItem component to provide the train stops. At runtime ADF Faces dynamically creates the nodeStamp facet and commandNavigationItem component, and automatically binds the methods in the train stop model to the appropriate properties on the commandNavigationItem component. Example 20-25 shows the simplified binding for a train.

Tip:

If you need to collate information for the train stops from various places, then you will need to manually create the nodeStamp facet and the individual commandNavigationItem components that represent the train stops. For more information, see Section 20.9.3, "How to Bind to the Train Model in JSF Pages."

Example 20-25 Simplified Train Model Binding

<af:train value="#{simpleTrainModel}"/>

The MenuModel implementation of your train model must provide specific train behavior. Train behavior defines how you want to control the pages users can access based on the page they are currently visiting. ADF Faces supports two train behaviors: Plus One and Max Visited.

Suppose there are 5 pages or stops in a train, and the user has navigated from page 1 to page 4 sequentially. Currently the user is at page 4. Where the user can go next depends on which train behavior the train model implements:

  • Plus One behavior: the user can go to page 3 or page 5

  • Max Visited behavior: the user can visit pages 1 to 3 (previously visited) and page 5 because it is the next page in the sequence. If the user goes to page 2, the next page that the user can visit is page 1, 3 or 4. The user cannot visit page 5 because page 4 was the maximum visited train stop in the sequence.

To define and use a train for all pages in a multistep process:

  • Create a JSF navigation rule and the navigation cases for the train. Creating a navigation rule and its navigation cases for a train is similar to Section 20.8.1, "How to Create a Simple Page Hierarchy," where you create one global navigation rule that has the navigation cases for all the train stops in the train.

    Note:

    You may want to set the value of the redirect element to true for each navigation case that you define within the JSF navigation rule if each train stop is an individual page and you want the client browser's URL to reference each new page. If you enable partial page rendering, the displayed URL may be different. For more information about the redirect element, see the JavaServer Faces specification. For more information about partial page rendering, see Chapter 8, "Rerendering Partial Page Content."

  • Create a train model that implements a specific train behavior and provides the train stop items for stamping. This includes creating a train stop model class and a menu model class. See Section 20.9.1, "How to Create the Train Model."

  • Configure managed beans for the train model. See Section 20.9.2, "How to Configure Managed Beans for the Train Model."

  • Create a JSF page for each train stop.

  • On each page, bind the train component to the train model. See Section 20.9.3, "How to Bind to the Train Model in JSF Pages." Optionally, bind the trainButtonBar component to the same train model if you want to provide additional navigation buttons for the train.

20.9.1 How to Create the Train Model

To define a train menu model, you create:

  • A train stop model that provides data for rendering a train stop.

  • A MenuModel implementation with a specific train behavior (like Max Visited or Plus One) that controls what stops along the train users can visit while visiting at a current train stop, which stops should be disabled or whether the train needs to be navigated sequentially or not, among other things.

ADF Faces makes it easier for you to define a train menu model by providing additional public classes, such as:

  • The abstract class TrainStopModel for implementing a train stop model.

  • The classes ProcessMenuModel and ProcessUtils that implement the Max Visited and Plus One behaviors.

Users can either implement their own custom train behavior by overriding MenuModel or extend the existing ProcessMenuModel to provide specialized behavior.

For examples of train model classes, see the oracle.adfdemo.view.nav.rich package of the ADF Faces Demonstration application.

Before you begin:

It may help to understand how a train component's attributes affect functionality. For more information, see Section 20.9, "Using Train Components to Create Navigation Items for a Multistep Process."

You may also find it helpful to understand functionality that can be added using other ADF Faces features. For more information, see Section 20.1.2, "Additional Functionality for Navigation Components."

To create the train model:

  1. Create a train stop model class. A train stop model object holds the row data for stamping each train stop. The train stop model implementation you create should set and get the properties for each stop in the train, and define the methods required to render a train stop. The properties of a train stop correspond to the properties of the commandNavigationItem component. This will allow you to use the simplified binding, as shown in Example 20-25.

    Alternatively, you can extend the abstract class TrainStopModel, and implement the abstract methods in the subclass.

    The properties on the commandNavigationItem component that will be automatically EL bound are:

    • action: A static action outcome or a reference to an action method that returns an action outcome. The outcome is used for page navigation through the default ActionListener mechanism in JSF.

    • disabled: A boolean value that indicates whether or not the train stop should be noninteractive. Note that the train behavior you elect to use affects the value of this property. For more information, see Step 2.

    • immediate: A boolean value that determines whether or not data validations should be performed. Note that the train behavior you elect to use affects the value of this property. For more information, see Step 2.

    • messageType: A value that specifies a message alert icon over the train stop image. Possible values are none, error, warning, and info, and complete. For more information about messages, see Chapter 19, "Displaying Tips, Messages, and Help."

    • shortDesc: A value that is commonly used by client user agents to display as tooltip help text for the train stop.

    • showRequired: A boolean value that determines whether or not to display an asterisk next to the train stop to indicate that required values are contained in that train stop page.

    • textAndAccessKey: A single value that sets both the label text to display for the train stop, as well as the access key to use.

    • visited: A boolean value that indicates whether or not the train stop has already been visited. Note that the train behavior you elect to use affects the value of this property. For more information, see Step 2.

  2. Create a class based on the MenuModel class to facilitate the construction of a train model.

    The MenuModel implementation of your train model must have a specific train behavior. The ProcessMenuModel class in the org.apache.myfaces.trinidad.model package is a reference implementation of the MenuModel class that supports the two train behaviors: Plus One and Max Visited. To implement a train behavior for a train model, you can either extend the ProcessMenuModel class, or create your own.

    In your train model class, you override the getFocusRowKey() method (see the MenuModel class) and implement a train behavior (see the ProcessMenuModel and ProcessUtils classes).

    The train behaviors provided in the ProcessMenuModel class have an effect on the visited, immediate, and disabled properties of the commandNavigationItem component.

    The visited attribute is set to true only if that page in the train has been visited. The ProcessMenuModel class uses the following logic to determine the value of the visited attribute:

    • Max Visited: A max visited stop is the farthest stop the user has visited in the current session. The visited attribute is set to true for any stop if it is before a max visited stop, or if it is the max visited stop itself.

    • Plus One: A plus one stop does not keep track of the farthest stop that was visited. The visited attribute is set to true for the current stop, or a stop that is before the current stop.

    When the data on the current page does not have to be validated, the immediate attribute should be set to true. Suppose page 4 in the Plus One behavior described earlier has data that must be validated. If the user has advanced to page 4 and then goes back to page 2, the user has to come back to page 4 again later to proceed on to page 5. This means the data on page 4 does not have to be validated when going back to page 1, 2, or 3 from page 4, but the data should be validated when going ahead to page 5. For more information about how the immediate attribute works, see Section 5.2, "Using the Immediate Attribute."

    The ProcessMenuModel class uses the following logic to determine the value of the immediate attribute:

    • Plus One: The immediate attribute is set to true for any previous step, and false otherwise.

    • Max Visited: When the current page and the maximum page visited are the same, the behavior is the same as the Plus One scenario. If the current page is before the maximum page visited, then the immediate attribute is set to false.

      Note:

      In an application that uses the ADF Model layer, the pageDefinition element in a page definition file supports an attribute (SkipValidation) that, when set to true, skips data validation for the page. Set SkipValidation to true if you want users to navigate from the page without invoking data validation. For more information, see the "pageNamePageDef.xml" section in Developing Fusion Web Applications with Oracle Application Development Framework.

    The disabled attribute is set to true only if that page in the train cannot be reached from the current page. The ProcessMenuModel class uses the following logic to determine the value of the disabled attribute:

    • Plus One: The disabled attribute will be true for any page beyond the next available page.

    • Max Visited: When the current stop and the maximum page visited are the same, the behavior is the same as the Plus One behavior. If the current page is before the maximum page visited, then disabled is set to true for any page beyond the maximum page visited.

By default, ADF Faces uses the Max Visited behavior when a non-null maxPathKey value is passed into the train model, as determined by the managed bean you will create to support the behavior (For more information, see Section 20.9.2, "How to Configure Managed Beans for the Train Model"). If the maxPathKey value is null, then ADF Faces uses the Plus One behavior.

20.9.2 How to Configure Managed Beans for the Train Model

You use managed beans in a train model to gather the individual train stops into an Arraylist object, which is turned into the tree model that is then injected into a menu model to bind to the value attribute of the train component. You must instantiate the beans with the proper values for injection into the models, and you also have to configure a managed bean for each train stop or page in the train.

Before you begin:

It may help to understand how a train component's attributes affect functionality. For more information, see Section 20.9, "Using Train Components to Create Navigation Items for a Multistep Process."

You may also find it helpful to understand functionality that can be added using other ADF Faces features. For more information, see Section 20.1.2, "Additional Functionality for Navigation Components."

To configure managed beans for the train model:

  1. Configure a managed bean for each stop in the train, with values for the properties that require setting at instantiation, to create the train stops to pass into an ArrayList.

    If a train stop has subprocess train children, there should be a managed bean for each subprocess train stop as well.

    Each bean should be an instance of the train stop model class created in Section 20.9.1, "How to Create the Train Model." Example 20-26 shows sample managed bean code for train stops in the faces-config.xml file.

    Example 20-26 Managed Beans for All Train Stops

    <!-- First train stop -->
    <managed-bean>
      <managed-bean-name>train1</managed-bean-name>
      <managed-bean-class>project1.DemoTrainStopModel</managed-bean-class>
      <managed-bean-scope>none</managed-bean-scope>
      <managed-property>
        <property-name>viewId</property-name>
        <value>/train.jsf</value>
      </managed-property>
      <managed-property>
        <property-name>outcome</property-name>
        <value>guide.train</value>
      </managed-property>
      <managed-property>
        <property-name>label</property-name>
        <value>First Step</value>
      </managed-property>
      <managed-property>
        <property-name>model</property-name>
        <value>trainMenuModel</value>
      </managed-property>
    </managed-bean>
    ...
    <!-- Second train stop -->
    <managed-bean>
      <managed-bean-name>train2</managed-bean-name>
      <managed-bean-class>project1.DemoTrainStopModel</managed-bean-class>
      <managed-bean-scope>none</managed-bean-scope>
      <managed-property>
        <property-name>viewId</property-name>
        <value>/train2.jsf</value>
      </managed-property>
      <managed-property>
        <property-name>outcome</property-name>
        <value>guide.train2</value>
      </managed-property>
      <managed-property>
        <property-name>label</property-name>
        <value>Second Step</value>
      </managed-property>
      <managed-property>
        <property-name>model</property-name>
        <value>trainMenuModel</value>
      </managed-property>
    </managed-bean>
    ...
    <!-- And so on -->
    ...
    

    The managed properties set the values to the train stop model object (the class created in Step 1 in Section 20.9.1, "How to Create the Train Model").

    The viewId value is the path and file name to the page that is navigated to when the user clicks a train stop.

    The outcome property value is the action outcome string that matches a JSF navigation case. The default JSF ActionListener mechanism is used to choose the page associated with the train stop as the view to navigate to when the train stop is selected.

    The label property value is the train stop label text that displays beneath the train stop image. The value can be static or an EL expression that evaluates to a string in a resource bundle.

    The model property value is the managed bean name of the train model (see Example 20-30).

    If a train stop has subprocess train children, the managed bean configuration should also include the property (for example, children) that lists the managed bean names of the subprocess train stops in value expressions (for example, #{train4a}), as shown in Example 20-27.

    Example 20-27 Managed Bean for a Train Stop with Subprocess train Children

    <managed-bean>
      <managed-bean-name>train4</managed-bean-name>
      <managed-bean-class>project1.DemoTrainStopModel</managed-bean-class>
      <managed-bean-scope>none</managed-bean-scope>
      <managed-property>
        <property-name>viewId</property-name>
        <value>/train4.jsf</value>
      </managed-property>
      <managed-property>
        <property-name>outcome</property-name>
        <value>guide.train4</value>
      </managed-property>
      <managed-property>
        <property-name>label</property-name>
        <value>Fourth Step</value>
      </managed-property>
      <managed-property>
        <property-name>children</property-name>
        <list-entries>
          <value-class>project1.DemoTrainStopModel</value-class>
          <value>#{train4a}</value>
          <value>#{train4b}</value>
          <value>#{train4c}</value>
        </list-entries>
      </managed-property>
      <managed-property>
        <property-name>model</property-name>
        <value>trainMenuModel</value>
      </managed-property>
    </managed-bean>
    
  2. Configure a managed bean that is an instance of an ArrayList object to create the list of train stops to pass into the train tree model.

    Example 20-28 shows sample managed bean code for creating the train stop list.

    Example 20-28 Managed Bean for Train List

    <managed-bean>
      <managed-bean-name>trainList</managed-bean-name>
      <managed-bean-class>
        java.util.ArrayList
      </managed-bean-class>
      <managed-bean-scope>
        none
      </managed-bean-scope>
      <list-entries>
        <value-class>project1.DemoTrainStopModel</value-class>
        <value>#{train1}</value>
        <value>#{train2}</value>
        <value>#{train3}</value>
        <value>#{train4}</value>
        <value>#{train5}</value>
      </list-entries>
    </managed-bean>
    

    The list-entries element contains the managed bean names for the train stops (excluding subprocess train stops) in value expressions (for example, #{train1}), listed in the order that the stops should appear on the train.

  3. Configure a managed bean to create the train tree model from the train list.

    The train tree model wraps the entire train list, including any subprocess train lists. The train model managed bean should be instantiated with a childProperty value that is the same as the property name that represents the list of subprocess train children (see Example 20-27).

    Example 20-29 Managed Bean for Train Tree Model

    <managed-bean>
      <managed-bean-name>trainTree</managed-bean-name>
        <managed-bean-class>
         org.apache.myfaces.trinidad.model.ChildPropertyTreeModel
        </managed-bean-class>
      <managed-bean-scope>none</managed-bean-scope>
      <managed-property>
        <property-name>childProperty</property-name>
        <value>children</value>
      </managed-property>
      <managed-property>
        <property-name>wrappedData</property-name>
        <value>#{trainList}</value>
      </managed-property>
    </managed-bean>
    

    The childProperty property defines the property name to use to get the child list entries of each train stop that has a subprocess train.

    The wrappedData property value is the train list instance to wrap, created by the managed bean in Step 2.

  4. Configure a managed bean to create the train model from the train tree model.

    This is the bean to which the train component on each page is bound. The train model wraps the train tree model. The train model managed bean should be instantiated with a viewIdProperty value that is the same as the property name that represents the pages associated with the train stops.

    Example 20-30 shows sample managed bean code for a train model.

    Example 20-30 Managed Bean for Train Model

    <managed-bean>
      <managed-bean-name>trainMenuModel</managed-bean-name>
        <managed-bean-class>
         org.apache.myfaces.trinidad.model.ProcessMenuModel
        </managed-bean-class>
      <managed-bean-scope>session</managed-bean-scope>
      <managed-property>
        <property-name>viewIdProperty</property-name>
        <value>viewId</value>
      </managed-property>
      <managed-property>
        <property-name>wrappedData</property-name>
        <value>#{trainTree}</value>
      </managed-property>
      <!-- to enable plusOne behavior instead, comment out the maxPathKey property -->
      <managed-property>
        <property-name>maxPathKey</property-name>
        <value>TRAIN_DEMO_MAX_PATH_KEY</value>
      </managed-property>
    </managed-bean>
    

    The viewIdProperty property value is set to the property that is used to specify the page to navigate to when the user clicks the train stop.

    The wrappedData property value is the train tree instance to wrap, created by the managed bean in Step 3.

    The maxPathKey property value is the value to pass into the train model for using the Max Visited train behavior. ADF Faces uses the Max Visited behavior when a non-null maxPathKey value is passed into the train model. If the maxPathKey value is null, then ADF Faces uses the Plus One behavior.

20.9.3 How to Bind to the Train Model in JSF Pages

Each stop in the train corresponds to one JSF page. On each page, you use one train component and optionally a trainButtonBar component to provide buttons that allow the user to navigate through the train.

Before you begin:

It may help to understand how a train component's attributes affect functionality. For more information, see Section 20.9, "Using Train Components to Create Navigation Items for a Multistep Process."

You may also find it helpful to understand functionality that can be added using other ADF Faces features. For more information, see Section 20.1.2, "Additional Functionality for Navigation Components."

To bind the train component to the train model:

  1. In the Components window, from the General Controls panel, in the Location group, drag and drop a Train onto the JSF page. Optionally drag and drop a Train Button Bar.

  2. Bind the component. If your MenuModel implementation for a train model returns a rowData object similar to the public abstract class oracle.adf.view.rich.model.TrainStopModel, you can use the simplified form of train binding in the train components, as shown in Example 20-31.

Example 20-31 Simple Implementation of a Train Component Bound to a Menu Model

<af:train value="#{trainMenuModel}"/>
<af:trainButtonBar value="#{trainMenuModel}"/>

The trainMenuModel EL expression is the managed bean name for the train model (see Example 20-30).

If you cannot use the simplified binding, you must bind the train value to the train model bean, manually add the nodeStamp facet to the train, and to that, add a commandNavigationItem component, as shown in Example 20-32.

Example 20-32 commandNavigationItem component Bound to a Train Stop

<af:train value="#{aTrainMenuModel}" var="stop">
  <f:facet name="nodeStamp">
    <af:commandNavigationItem
      text="#{stop.label}"
      action="#{stop.outcome}"
      ...
    </af:commandNavigationItem>
  </f:facet>
</af:train>