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:
Section 18.3, "Configuring a Browser's Context Menu for Command Links"
Section 18.4, "Using Buttons or Links to Invoke Functionality"
Section 18.6, "Using a Menu Model to Create a Page Hierarchy"
Section 18.8, "Using Train Components to Create Navigation Items for a Multi-Step Process"
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:
Button and link components for navigating to another location with or without server-side actions. See Section 18.2, "Using Buttons and Links for Navigation".
Components that render items such as tabs and breadcrumbs for navigating hierarchical pages. See Section 18.5, "Using Navigation Items for a Page Hierarchy".
Train components for navigating a multistep process. See Section 18.8, "Using Train Components to Create Navigation Items for a Multi-Step Process".
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".
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.
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.
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 thedocument
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.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:
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.
In the Property Inspector, expand the Common section and set the text
attribute.
Tip:
Alternatively, you can use thetextAndAccessKey
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"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 thetext
attribute (or textAndAccessKey
attribute) or the icon
attribute, or both.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:
TheactionListener
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.
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.
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".
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".
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 thedocument
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".
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:
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.
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 thetextAndAccessKey
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"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 thetext
attribute (or textAndAccessKey
attribute) or the icon
attribute, or both.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"
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.
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.
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
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
.
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:
In the Application Navigator, double-click web.xml to open the file.
By default, JDeveloper opens the web.xml
file in the Overview editor.
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
.
Save and close the web.xml
file.
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."
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:
exportCollectionActionListener
: Use to export data from an ADF Faces application to an Excel spreadsheet. For more information, see Section 10.11, "Exporting Data from Table, Tree, or Tree Table".
fileDownloadActionListener
: Use to initiate a file download from the server to the local computer. For more information, see Section 18.4.1, "How to Use a Command Component to Download Files".
resetActionListener
: Use to reset submitted values. However, no data model states will be altered. For more information, see Section 18.4.2, "How to Use a Command Component to Reset Input Fields". If you want to reset the input components to their previous state, which was partially or fully submitted successfully to the server, then you can use a reset button. For more information, see Section 9.2.3, "How to Add a Reset Button to a Form".
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.
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:
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").
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.
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>
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".
Create a command component as documented in Section 18.2, "Using Buttons and Links for Navigation".
Drag and drop a Reset Action Listener from the Component Palette as a child to the command component.
Note:
If your application uses the Fusion technology stack with the ADF Controller, then you should use ADF task flows and anXMLMenuModel
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.
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.
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.
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".Note:
If your application uses the Fusion technology stack or the ADF Controller, then you should use ADF task flows and anXMLMenuModel
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 thenavigationPane
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:
Create the JSF navigation rule and navigation cases for the page hierarchy and then create the XMLMenuModel
metadata. See Section 18.6.1, "How to Create the Menu Model Metadata".
Configure the managed bean for the XMLMenuModel
class. The application uses the managed bean to build the hierarchy. This configuration is automatically done for you when you use the Create ADF Menu Model dialog in JDeveloper to create the XMLMenuModel
metadata file. See Section 18.6.2, "What Happens When You Use the Create ADF Menu Model Wizard".
Create a JSF page for each of the hierarchical nodes (including any global nodes).
Tip:
Typically, you would use a page template that contains a facet for each level of items (including global items and breadcrumbs) to create each JSF page. For example, thenavigationPane
component representing global items might be wrapped in a facet named navigationGlobal
, and the navigationPane
component representing first level tabs might be wrapped in a navigation1
facet. For information about creating page templates, see Chapter 19, "Creating and Reusing Fragments, Page Templates, and Components".On each page, bind the navigationPane
and breadCrumbs
components to the XMLMenuModel
class. See Section 18.6.3, "How to Bind to the XMLMenuModel in the JSF Page" and Section 18.6.4, "How to Use the breadCrumbs Component".
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.
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:
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".
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.In the Create ADF Menu Model dialog, enter a file name for the XMLMenuModel
metadata file, for example, root_menu
.
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".
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 |
---|---|
|
Optional. This is the resource bundle to use for the labels (visible text) of the navigation items at runtime. For example, |
|
If using a resource bundle, specify an ID to use to reference the bundle in EL expressions for navigation item labels. For example, |
|
Required. Set to |
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 asharedNode
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".
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.
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.
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.
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 |
---|---|
|
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 |
|
Specify the URI of the page to navigate to when the node is selected, for example, Alternatively, specify an EL method expression that evaluates to the URI. If both |
|
Required. The URI of the page that matches the node's navigational result, that is, the For example, if the action outcome of the node navigates to The |
|
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 |
|
Specify the label text to display for the node. Can be an EL expression to a string in a resource bundle, for example, |
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 |
---|---|
|
A unique identifier for the group node. As shown in Example 18-4, it is good practice to use |
|
Specify the ID of a child node, which can be an The |
|
Specify the label text to display for the group node. Can be an EL expression to a string in a resource bundle, for example, |
Table 18-4 sharedNode Element Attribute
Attribute | Description |
---|---|
|
Specify the managed bean name of another At runtime, the referenced navigation menu is created, inserted as a submenu into the main (root) menu, and rendered. |
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.
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 eachnavigationPane
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 theXMLMenuModel
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:
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".
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.
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.
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.
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:
Thevalue
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.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 thevar
attribute for every navigationPane
component on the page or in the application.Drag and drop a Navigation Item from the Component Palette to the nodeStamp
facet of the navigationPane
component.
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>
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.
Create a breadCrumbs
component by dragging and dropping a Bread Crumbs component from the Component Palette to the JSF page.
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
.
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:
Thevalue
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.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 thevar
attribute for the breadCrumbs
component as you did for the navigationPane
components on the page or in the application.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:
ThenodeStamp
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.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.
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.
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; }
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.
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.
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.
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:
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".
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".
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.
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.
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 anavigationPane
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.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.
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>
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.
Create a breadCrumbs
component by dragging and dropping a Bread Crumbs component from the Component Palette to the JSF page.
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
.
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 thecommandNavigationItem
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.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 individualcommandNavigationItem
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".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 ... } } }
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.
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.
For more information about skinning, see Chapter 20, "Customizing the Appearance Using Styles and Skins."
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.
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.
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.
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 individualcommandNavigationItem
components that represent the train stops. For more information, see Section 18.8.3, "How to Bind to the Train Model in JSF Pages".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 theredirect
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.
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.
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.
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, thepageDefinition
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 "pageName
PageDef.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.
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:
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>
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.
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.
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.
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:
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.
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.