18 Working with Navigation Components

This chapter describes how to use ADF Faces navigation components such as commandButton, navigationPane, and train to provide navigation in web user interfaces.

This chapter includes the following sections:

18.1 Introduction to 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 (or other 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 4, "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 Section 7.4, "Using Partial Page Navigation".

Command components in ADF Faces include:

In addition to using command components for navigation, ADF Faces also includes listener tags that you can use in conjunction with command components to have specific functionality execute when the action event fires. For more information, see Section 18.4, "Using Buttons or Links to Invoke Functionality".

18.2 Using Buttons and Links for Navigation

Buttons and links in ADF Faces include the command components commandButton, commandLink, and commandImageLink, as well as the go components goButton, goImageLink, and goLink. The main difference between command components and go components is that while command components submit requests and fire ActionEvent events, go components navigate directly to another location without delivering an action. Visually, the rendered command and go components look the same, as shown in Figure 18-11.

Figure 18-1 Command Components and Go Components

Command Components and Go Components

Tip:

ADF Faces also provides specialized command components that can be used inside menus and toolbars. For more information, see Chapter 14, "Using Menus, Toolbars, and Toolboxes".

The commandImageLink and goImageLink components render images as links, along with optional text, as shown in Figure 18-2. 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.

Figure 18-2 Command Image Link and Go Image Link

Command Image Link and Go Image Link

ADF Faces also includes a toolbar button that provides additional functionality, such as a popup facet that can open popup menus from a toolbar button. For more information, see Section 14.3, "Using Toolbars".

You can configure your application to allow end users invoke a browser's context menu when they right-click a command component that renders a link. End users who right-click the link rendered by a command 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 18.3, "Configuring a Browser's Context Menu for Command Links."

You can show a warning message to users if the page that they attempt to navigate away from contains uncommitted data. Add the checkUncommittedDataBehavior component as a child to command 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 following components:

  • af:commandButton

  • af:commandLink

  • af:commandImageLink

  • af:commandToolbarButton

  • af:activeCommandToolbarButton

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 8.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 of the Oracle Fusion Middleware Fusion Developer's Guide for Oracle Application Development Framework.

18.2.1 How to Use Command Buttons and Command Links

Typically, you use commandButton, commandLink, and commandImageLink components to perform page navigation and to execute any server-side processing.

To create and use command components:

  1. Create a commandButton component by dragging and dropping a Button from the Component Palette to the JSF page. Create a commandLink component by dragging and dropping a Link. Create a commandImageLink component by dragging and dropping an Image Link.

  2. In the Property Inspector, expand the Common section and set the text attribute.

    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 22.3.4, "How to Define Access Keys for an ADF Faces Component"
  3. Set the icon attribute to the URI of the image file you want to use for inside a commandButton or commandImageLink component (this is not supported for commandLink). For a commandImageLink component, you can also set the hoverIcon, disabledIcon, and depressedIcon attributes.

    Tip:

    You can use either the text attribute (or textAndAccessKey attribute) or the icon attribute, or both.
  4. Set the action attribute 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 2.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 13, "Using Popup Dialogs, Menus, and Windows". For more information about outcome strings and navigation in JSF applications, see the Java EE 6 tutorial at https://download.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 is used to perform 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.

  5. Expand the Behavior section and set the disabled attribute to true if you want to show the component as a non-interactive button or link.

  6. Set the partialSubmit attribute to true to fire a partial page request each time the component is activated. For more information, see Section 7.2, "Enabling Partial Page Rendering Declaratively".

  7. Set the immediate attribute to true if you want 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 4.2, "Using the Immediate Attribute".

  8. Optionally, if you set the immediate attribute to true as described in step 7, you can add the af:checkUncommittedDataBehavior component as a child to the command component to display a warning message to the user if the page contains uncommitted data. Drag the Check Uncommitted Data Behavior from the Behavior section of the Operations panel in the Component Palette and drop it as a child of the command component you added in step 1.

    Note:

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

Command 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 Chapter 18, "Working with Navigation Components".

18.2.2 How to Use Go Buttons and Go Links

You use the goButton, goImageLink, and goLink components to perform direct page navigation, without delivering an ActionEvent event.

To create and use go buttons and go links:

  1. Create a goButton component by dragging and dropping a Go Button from the Component Palette to the JSF page. Create a goLink component by dragging and dropping a Go Link. Create a goImageLink component by dragging and dropping a Go Image Link.

  2. In the Property Inspector, expand the Common section and set the text attribute if you created a goButton or goLink component. If you created a goImageLink component, you set the text attribute in the Other section.

    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 22.3.4, "How to Define Access Keys for an ADF Faces Component"
  3. Set the icon attribute to the URI of the image file you want to use for inside a goButton or goImageLink component (not supported for goLink). For a goImageLink component, you can also set the hoverIcon, disabledIcon, depressedIcon, and iconPosition attributes.

    The iconPosition attribute supports two values: leading (default) and trailing. Set to leading to render the icon before the text. Set to trailing to render the icon after the text.

    Tip:

    You can use either the text attribute (or textAndAccessKey attribute) or the icon attribute, or both.
  4. Set the destination attribute to the URI of the page to which the link should navigate.

    For example, in the File Explorer application, the goLink component in the popups.jspx file has the following EL expression set for its destination attribute:

    destination="http://www.oracle.com"
    
  5. Set the targetFrame attribute to specify where the new page should display. Acceptable values are:

    • _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.

  6. Expand the Behavior section and set the disabled attribute to true if you want to show the component as a non-interactive button or link. You set the disabled attribute for the goImageLink component in the Other section.

18.3 Configuring a Browser's Context Menu for Command Links

The command 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 command components. 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 command component. The components for which you can configure this behavior include the following:

  • af:commandLink

  • af:commandImageLink

  • af:commandMenuItem (stand-alone or 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. Examples of these components include the following:

  • af:goLink

  • af:goImageLink

  • af:commandNavigationItem where you specify a value for the destination attribute and no value for the action attribute

18.3.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 command components you can configure this functionality for. For more information, Section 18.3, "Configuring a Browser's Context Menu for Command Links."

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

  1. In the Application Navigator, double-click web.xml to open the file.

    By default, JDeveloper opens the web.xml file in the Overview editor.

  2. In the Context Initialization Parameters table, 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.

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

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

Example 18-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 18.3, "Configuring a Browser's Context Menu for Command Links."

18.4 Using Buttons or Links to Invoke Functionality

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

18.4.1 How to Use a Command Component to Download Files

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

Figure 18-3 File Download Dialog

File Download Dialog

The fileDownloadActionListener tag is used declaratively to allow an action component such as command button, command link, or menu item to programmatically send the contents of a file to the user. You can also declare a specific content type or file name. Because file download must be processed with an ordinary request instead of the XMLHttp AJAX requests, the parent component's partialSubmit attribute, if supported, must be set to false.

Tip:

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

After the content has been sent to the browser, how that content is displayed or saved depends on the option selected in the dialog. If the Open with option was selected, 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 Save to Disk option was selected, depending on the browser, a popup dialog may appear to select a file name and a location in which to store the content.

Example 18-2 shows the tags of a command button with the fileDownloadActionListener tag to download the file content Hi there! to the user.

Example 18-2 File Download Using Command Button and fileDownloadActionListener Tag

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

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

Example 18-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!");
   . . .
}

To create a file download mechanism:

  1. From the Component Palette, drag and drop any action component to your page (for more information about action components, see Section 18.2, "Using Buttons and Links for Navigation").

  2. Expand the Operations section of the Component Palette, and drag and drop the File Download Action Listener tag as a child to the action component.

  3. In the Property Inspector 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 be used to 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, the code for a command button would be similar to the following:

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

18.4.2 How to Use a Command Component to Reset Input Fields

You can use the resetActionListener tag in conjunction with a command component to reset input values. All values will be returned 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 9.2.3, "How to Add a Reset Button to a Form".

To use the reset tag:

  1. Create a command component as documented in Section 18.2, "Using Buttons and Links for Navigation".

  2. Drag and drop a Reset Action Listener from the Component Palette as a child to the command component.

18.5 Using Navigation Items for a Page Hierarchy

Note:

If your application uses the Fusion technology stack with the 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" section of the Oracle Fusion Middleware Fusion Developer's Guide for 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 18-4 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 18-4 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 18-4, 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 a page hierarchy are tabs, bars, lists, and global links, all of which can be created by using the navigationPane component. Figure 18-5 shows the hierarchy illustrated in Figure 18-4, as rendered using the navigationPane and other components.

Figure 18-5 Rendered Benefits and Employee Pages

Hiearchical menu components in a page

In general, tabs are used as first-level nodes, as shown in Figure 18-5, where there are tabs for the Benefits and Employee Detail 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 use tabs for both first- and second-level nodes. Global links (which represent global nodes) are rendered as text links. In Figure 18-5, 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 navigation items the navigationPane component is configured to render for a level, you always use the commandNavigationItem component to represent each item within the navigationPane component.

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 18-10 and Figure 18-11, 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 20, "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 19.3, "Using Page Templates".

For each page of simpler 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 links for each level. For example, to create the Health insurance page as shown in Figure 18-5, 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. If instead you were creating the Benefits page, as shown in Figure 18-6, you would create only three navigationPane components (one each for the global, first, and second levels), and then create just the commandNavigationItem components for the links seen from this page.

Figure 18-6 First-Level Page

First-Level Page

As you can see, with large 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. 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 JSF navigation model, through the default ActionListener mechanism, is used to choose the page to navigate to when users select a navigation item. For more information about the menu model, see Section 18.6, "Using a Menu Model to Create a Page Hierarchy".

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 18.6, "Using a Menu Model to Create a Page Hierarchy". For more information about manually creating a navigational hierarchy, see Section 18.7, "Creating a Simple Navigational 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 14, "Using Menus, Toolbars, and Toolboxes".

18.6 Using a Menu Model to Create a Page Hierarchy

Note:

If your application uses the Fusion technology stack or the 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" section of the Oracle Fusion Middleware Fusion Developer's Guide for Oracle Application Development Framework.

Section 18.5, "Using Navigation Items for a Page Hierarchy" describes how you can create a navigation menu 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 menu 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 10.5, "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 XMLMenuModel class to create the menu model.

Performance Tip:

Using the navigationPane component with the menu model results in a full page refresh every time the user switches the tab. Instead, you can use the panelTabbed component (see Section 8.11, "Displaying or Hiding Contents in Panels". This component has built-in support for partial page rendering of the tabbed content. However, it 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:

18.6.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. In the XMLMenuModel metadata file, the entire 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.

The remaining nodes in the 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 as depicted in Figure 18-7.

Figure 18-7 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 you would create an item node in the metadata for each page. You nest the children nodes inside the 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.

You can also nest menu models using the shared nodes. This approach is recommended 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 model so that it could be reused across an application. Instead of creating the nodes for each use, you could instead create the nodes once as a separate menu and then within the different hierarchies, use a shared node to reference the Benefits menu model.

Example 18-4 shows an XMLMenuModel metadata file for defining a page hierarchy illustrated in Figure 18-7.

Example 18-4 XMLMenuModel Metadata File Sample

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

Within the root menu element, global nodes are any types of nodes that are direct children of the menu element; in other words, the first level of elements under the menu element are global nodes. For example, the code in Example 18-4 shows three global nodes, namely, Home, Help, and Preferences. Within a first-level child node, nodes can be nested to provide more levels of navigation. For example, the code in Example 18-4 shows two second-level nodes under Home, namely, Benefits and Employee Data. Within Benefits, there are two third-level nodes, Insurance and Paid Time Off, and so on.

JDeveloper simplifies creating metadata for an XMLMenuModel class by providing the Create ADF Menu Model wizard.

To create the XMLMenuModel metadata:

  1. 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 18-4 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 18-5.

    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 18-5 Global Navigation Rule for a Page Hierarchy in faces-config.xml

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

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

  2. In the Application Navigator, locate the project where you wish to create the XMLMenuModel metadata file. Under the project's Web Content - WEB-INF folder, right-click the faces-config.xml file, and choose Create ADF Menu from the context menu.

    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" section of the Oracle Fusion Middleware Fusion Developer's Guide for Oracle Application Development Framework.
  3. In the Create ADF Menu Model dialog, enter a file name for the XMLMenuModel metadata file, for example, root_menu.

  4. Enter a directory for the metadata file. By default, JDeveloper will save the XMLMenuModel metadata file in the WEB-INF directory of the application.

    When you click OK, JDeveloper automatically does the following for you:

    • Creates a managed bean for the model in the faces-config.xml file, using the name specified in Step 3 for the managed bean name.

    • Sets the value of the managed bean's source managed property to the XMLMenuModel metadata file, specified in Step 3, for example, /WEB-INF/root_menu.xml.

    • Displays the source file (that is, /WEB-INF/root_menu.xml) as a blank XMLMenuModel metadata file in the source editor, as shown in Example 18-6.

    Example 18-6 Blank XMLMenuModel Metadata File

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

    For more information about the managed bean configuration JDeveloper automatically adds for you, see Section 18.6.2, "What Happens When You Use the Create ADF Menu Model Wizard".

  5. Select the menu node in the Structure window and enter the appropriate information in the Property Inspector.

    Table 18-1 shows the attributes you can specify for the menu element.

    Table 18-1 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 18-7 for a sample XMLMenuModel metadata file that uses a resource bundle.

    xmlns

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


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

    Example 18-7 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 quite 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 21, "Internationalizing and Localizing Pages".

  6. In the Structure window, add the desired elements for the nodes in your hierarchy, using itemNode, groupNode, or sharedNode as needed. To begin, right-click menu and choose Insert inside menu, and then choose the desired element from the context menu, as shown in Figure 18-8.

    Figure 18-8 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 18-8, the sharedNode element adds a submenu on the same level as the global nodes.

      Example 18-8 SharedNode Sample Code

      <?xml version="1.0" encoding="windows-1252" ?>
      <menu xmlns="http://myfaces.apache.org/trinidad/menu"
        <itemNode id="in1" label="Home" ../>
        <sharedNode ref="#{shared_menu}"/>
        <itemNode id="in6" 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 18-9.

    Figure 18-9 Tree Structure of XMLMenuModel Metadata in Structure Window

    Tree structure in Structure window
  7. For each element used to create a node, set the properties in the Property Inspector, as described in Table 18-2 for itemNode elements, Table 18-3 for groupNode elements, and Table 18-4 for sharedNode elements.

    Table 18-2 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.jspx (as configured in the faces-config.xml file), then focusViewId must also be /page_one.jspx.

    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 18-4, 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 18-9. 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 18-3 shows the attributes you must specify when you use a groupNode element.

    Example 18-9 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.jspx"/>
          <itemNode id="in2" label="LEVEL2_TAB_1" action="goToSubTabTwo"
                    focusViewId="/menuDemo/subtab2.jspx"/>
        </groupNode>
        <itemNode id="in3" label="PRIMARY_TAB_1" focusViewId="/menuDemo/tab2.jspx"
                  destination="/faces/menuDemo/tab2.jspx"/>
      </groupNode>
      <itemNode id="gin1" label="GLOBAL_TAB_1" action="goToGlobalOne" 
                focusViewId="/menuDemo/global1.jspx"/>
      <itemNode id="gin2" label="GLOBAL_TAB_2" 
                destination="/faces/menuDemo/global2.jspx"
                focusViewId="/menuDemo/global2.jspx"/>
    </menu>
    

    Table 18-3 GroupNode Element Attribute

    Attribute Description

    id

    A unique identifier for the group node.

    As shown in Example 18-4, 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 18-4 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.


18.6.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 metadata file in the faces-config.xml file, using the metadata file name you provide as the managed bean name.

Example 18-10 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 18-10 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 each 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 source menu metadata 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.

    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 this value already set to properly parse and create the menu's XML metadata from the source managed property.

  • source: Specifies the source metadata file to use.

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 18-8), 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 18-11.

Example 18-11 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>true</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 file, 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.

18.6.3 How to Bind to the XMLMenuModel in the JSF Page

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 18-4), 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 18-7 and Example 18-4, 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 18.7.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 XMLMenuModel managed bean, and insert only one commandNavigationItem component into the nodeStamp facet of each navigationPane component, as shown in Example 18-12.

Example 18-12 navigationPane Component Bound to XMLMenuModel Managed Bean

<af:navigationPane var="menuNode" value="#{root_menu}" level="1"
                   hint="tabs">
  <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 code for that level.

To bind to the XMLMenuModel managed bean:

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

    • default: Body is white with a blue border. Top-left corner is rounded.

    • light: Body is light blue. Top-left corner is rounded.

    • medium: Body is medium blue. Top-left corner is rounded.

    • dark: Body is dark blue. Top-left corner is rounded.

    You can change how the themes are displayed. For more information, see Chapter 20, "Customizing the Appearance Using Styles and Skins".

  2. Create a navigationPane component by dragging and dropping a Navigation Pane from the Component Palette to the JSF page. Add a navigationPane component for each level of the hierarchy.

    Tip:

    The Navigation Pane component can be found in the Layout pane of the Component Palette.

    For example, to create any of the pages as shown in the hierarchy in Figure 18-5, you would drag and drop four navigationPane components.

  3. For each navigationPane component, in the Property Inspector, expand the Common section and set the Hint attribute to one of the following types of navigation items to determine how the navigationPane will display the following:

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

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

    • 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 18-11.

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

  4. Set the level attribute to point to 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 18-4), 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.

  5. In the Property Inspector, expand the Data section. Set the value attribute 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.
  6. Set the var attribute 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.
  7. Drag and drop a Navigation Item from the Component Palette to the nodeStamp facet of the navigationPane component.

  8. 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 6 along with the name of the corresponding itemNode element that holds the value in the metadata. Table 18-5 shows the attributes on the navigation item that has corresponding values in the metadata.

    Table 18-5 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 18-13 shows the JSF code for binding to a menu model for the HR example.

    Example 18-13 Binding to the XML Model

    <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>
    

18.6.4 How to Use the breadCrumbs Component

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.

To create a breadcrumb:

  1. Create a breadCrumbs component by dragging and dropping a Bread Crumbs component from the Component Palette to the JSF page.

  2. By default, breadcrumb links are displayed in a horizontal line. To change the layout to be vertical, in the Property Inspector, expand the Common section and set the orientation attribute to vertical.

  3. In the Property Inspector, expand the Data section. Set the value attribute to the root menu model 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 18-8), 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.
  4. Set the var attribute 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.
  5. Add one commandNavigationItem component as a child by dragging and dropping a Navigation Item from the Component Palette to 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.
  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 breadCrumbs component in Step 4 along with the name of the corresponding itemNode element that holds the value in the metadata. Table 18-5 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 18-14 breadCrumbs Component Bound to a MenuModel

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

18.6.5 What Happens at Runtime

The value attribute of navigationPane component 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 navigationPane 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 navigationPane 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.

18.6.6 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 18-15 shows an example of the required code.

Example 18-15 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;
  }  

18.7 Creating a Simple Navigational Hierarchy

Figure 18-10 and Figure 18-11 show an example of what the user interface looks like when the navigationPane component and individual commandNavigationItem components are used to create a view for the page hierarchy shown in Figure 18-4.

Figure 18-10 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 navigationPanes and commandNavigationItem components needed for each page, as well as to determine whether or not each component should be configured as selected when the user visits the page. For example, in Figure 18-10, which shows the Employee Data page, only the child bars of Employee Data are needed, and the Employee Data tab renders as selected.

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

Figure 18-11 Navigation Items Available from the Health Page

Navigation items using NavigationPane

Regardless of the type of navigation items you use (such as tabs or bars), a series of commandNavigationItem child components within each navigationPane component provide the actual navigation items. For example, in Figure 18-11 the actual link for the Employee Data tab, the Insurance and Paid Time Off bars, and the Health and Dental links in the list are each provided by a commandNavigationItem component.

18.7.1 How to Create a Simple Page Hierarchy

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

To manually create a navigation hierarchy:

  1. 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 18-4 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 18-16.

    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 18-16 Global Navigation Rule for a Page Hierarchy in faces-config.xml

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

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

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

    • default: Body is white with a blue border. Top-left corner is rounded.

    • light: Body is light blue. Top-left corner is rounded.

    • medium: Body is medium blue. Top-left corner is rounded.

    • dark: Body is dark blue. Top-left corner is rounded.

    You can change how the themes are displayed. For more information, see Chapter 20, "Customizing the Appearance Using Styles and Skins".

  3. Create a navigationPane component by dragging and dropping a Navigation Pane from the Layout section of the Component Palette as a child to the decorativeBox component. Add a navigationPane component for each level of the hierarchy.

    For example, to create the Health page as shown in Figure 18-11, 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.

  4. For each navigationPane component, in the Property Inspector, expand the Common section and set the Hint attribute to one of the following types of navigation items to determine how the navigationPane component will be displayed:

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

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

    • 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 18-11.

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

  5. For each navigationPane component, add the needed commandNavigationItem components to represent the different links by dragging and dropping a Navigation Item from the Common Components section of the Component Palette. 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 18-11, you would use a total of six 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.
  6. For each commandNavigationItem component, set the navigation to the desired page. In the Property Inspector, expand the Common section and provide a static string outcome of an action or use an EL expression to reference an action method through the action property. If you use a string, it must match the navigation metadata set up in the navigation rules for the page created in Step 1. If referencing a method, that method must return the required string.

  7. In the Property Inspector, expand the Behavior section and set the selected attribute. This attribute should be true 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 and the appearance changes to indicate to the user that the item has been selected. For example, in Figure 18-11 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 18-17 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 18-17 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>

18.7.2 How to Use the breadCrumbs Component

In both Figure 18-10 and Figure 18-11, 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 create such a path of links, you use the breadCrumbs component with a series of commandNavigationItem components as children.

To create a breadcrumb:

  1. Create a breadCrumbs component by dragging and dropping a Bread Crumbs component from the Component Palette to the JSF page.

  2. By default, breadcrumb links are displayed in a horizontal line. To change the layout to be vertical, in the Property Inspector, expand the Common section and set the orientation attribute to vertical.

  3. For each link in the breadcrumb, create a commandNavigationItem component by dragging and dropping a Navigation Item from the Component Palette 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 Property Inspector, expand the Common section and provide a static string outcome of an action or use an EL expression to reference an action method through the action property. If you use a string, it must match the navigation metadata set up in the navigation rule for the page created in Step 1. 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 18-11, drag and drop four navigationPane components, as shown in Example 18-18.

Example 18-18 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>

Note:

Similarly, instead of using individual commandNavigationItem components, you can bind the value attribute of the breadCrumbs component to an XMLMenuModel implementation, and use one commandNavigationItem component in the nodeStamp facet of the breadCrumbs component to stamp out the items for a page. For information about the XMLMenuModel class, see Section 18.6, "Using a Menu Model to Create a Page Hierarchy".

18.7.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) is displayed 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 or how to handle child components). For more information about events, see Chapter 5, "Handling Events." For information about using popup dialogs and windows, see Chapter 13, "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 will handle the actual tab removal, as shown in Example 18-19.

Example 18-19 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 ...
    }
  }
}

18.7.4 What You May Need to Know About Skinning and Navigation Tabs

You can use the -tr-layout-type skinning key to configure the type of indicator that the navigationPane component renders in an application window that is in a compressed layout. That is, the application window is not wide enough to display all the navigation tabs.

Figure 18-12 shows an overflow indicator that renders a dropdown list where the user can choose the navigation tab to navigate to.

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

Overflow Indicator for a navigationPane Component

Example 18-20 shows how you configure the -tr-layout-type skinning key so that the navigationPane component displays an overflow indicator.

Example 18-20 Using a Skinning Key to Set the Compressed Layout to Overflow

af|navigationPane {
  -tr-layout-type: overflow;
}

Rather than display overflow indicators, as shown in Figure 18-12, 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 tabs that are not currently visible. Configuring the -tr-layout-type skinning key also renders all navigation tabs in one dropdown list, as shown in Figure 18-13. 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 overflow.

Example 18-21 shows how you configure the -tr-layout-type skinning key so that the navigationPane component renders a conveyor belt.

Example 18-21 Using a Skinning Key to Set the Compressed Layout to Conveyor Belt

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

Figure 18-13 shows the navigationPane component rendering a conveyor belt in a compressed layout.

Figure 18-13 Conveyor Belt for a navigationPane Component in Compressed Layout

Conveyor Belt for a navigationPane Component

For more information about skinning, see Chapter 20, "Customizing the Appearance Using Styles and Skins."

18.8 Using Train Components to Create Navigation Items for a Multi-Step Process

Note:

If your application uses the Fusion technology stack or the ADF Controller, then you should use ADF task flows to create the navigation system for your application page hierarchy. For details, see the "Creating a Train" section of the Oracle Fusion Middleware Fusion Developer's Guide for 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 18-14 shows an example of what a rendered train component might look like on a page. Not only does a train 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 18-14 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 be displayed. 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.

As shown in Figure 18-14, 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 a command component (for example, a commandButton 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 4 has a subprocess train containing three 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 18-15.

Figure 18-15 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 18-16. 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 18-16 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 "Creating a Train" section of the Oracle Fusion Middleware Fusion Developer's Guide for 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 10, "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 exposes 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, which you can create by extending the org.apache.myfaces.trinidad.model.ProcessMenuModel class. The train behavior controls what stops along the train users can visit while visiting at a 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.

Binding a train component to a train menu model is similar to binding a navigationPane component to an XMLMenuModel class (described in Section 18.6.3, "How to Bind to the XMLMenuModel in the JSF Page"). However, as long as your TrainStopModel implementation returns a rowData object, you do not need to provide the commandNavigationItem components for each stop. 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 18-22 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 18.8.3, "How to Bind to the Train Model in JSF Pages".

Example 18-22 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. At page 4 the user jumps back to page 2. Where the user can go next depends on which train behavior is used in the train model.

In Max Visited, from the current page 2 the user can go back to page 1, go ahead to page 3, or jump ahead to page 4. That is, Max Visited allows the user to return to a previous page or advance to any page up to the farthest page already visited. The user cannot jump ahead to page 5 from page 2 because page 5 has not yet been visited.

Given the same situation, in the Plus One behavior the user can only go ahead to page 3 or go back to page 1. That is, Plus One allows the user to return to a previous page or advance one more stop further than the current stop. The user cannot jump ahead to page 4 even though page 4 has already been visited.

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 18.7.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 7, "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 18.8.1, "How to Create the Train Model".

  • Configure managed beans for the train model. See Section 18.8.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 18.8.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.

18.8.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 (either 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 for implementing a train behavior for the train model

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

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 18-22.

    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 non-interactive. 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 17, "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. visited 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 4.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 the Oracle Fusion Middleware Fusion Developer's Guide for 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 18.8.2, "How to Configure Managed Beans for the Train Model"). If the maxPathKey value is null, then ADF Faces uses the Plus One behavior.

18.8.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 create the train model. 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.

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 18.8.1, "How to Create the Train Model". Example 18-23 shows sample managed bean code for train stops in the faces-config.xml file.

    Example 18-23 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.jspx</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.jspx</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 18.8.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 18-27).

    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 18-24.

    Example 18-24 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.jspx</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 18-25 shows sample managed bean code for creating the train stop list.

    Example 18-25 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 18-24).

    Example 18-26 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 18-27 shows sample managed bean code for a train model.

    Example 18-27 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.

18.8.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.

To bind the train component to the train model:

  1. Create a train component by dragging and dropping a Train from the Component Palette to 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 the following code:

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

The trainMenuModel in the EL expression is the managed bean name for the train model (see Example 18-27).

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 18-28.

Example 18-28 Metadata to Bind a Train Component to the Train Model Bean

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