Core ADF 11: Mapping Multiple FocusViewId's with XMLMenuModel
By Steven Davelaar on Apr 16, 2009
In the first post of this Core ADF 11 series, I discussed various options for designing your page structure. This post applies when you use stand-alone .jspx pages. If you make these pages available through a menu (af:navigationPane) using XMLMenuModel where each menu item navigates to a page (either in the unbounded task flow or by calling a bounded task flow), the menu tab will be automatically highlighted when you set the focusViewId property of the itemNode in the XML Menu Model file to the name of the .jspx page that appears when you click on the menu item. Unfortunately, you can specify only one focusViewId for an itemNode. If your .jspx page has a button or link to navigate to a secondary page, you will loose the menu item highlighting because the focusViewId of the menu itemNode no longer matches the view id of the current (secondary) page. Even worse, if you have nested itemNodes defined in the XML Menu Model, the submenu that was displayed with the primary page will disappear when navigating to the secondary page.
The "poor-man's solution" to this problem is adding nested item nodes to the XML Menu Model for the detail pages. This technique is easy but can only be applied when there is no page-specific submenu that should be displayed with the pages. You simply create child itemNodes in the XML Menu model for the detail pages in the task flow, which will never be displayed as menu items because you do not include an af:navigationPane that displays this menu level.
A more sophisticated solution, that allows for page-specific submenus, is to subclass XMLMenuModel. The subclass looks up a MenuViewIdMapping managed bean that maps all viewIds of the secondary pages in the task flow to the viewId of the primary page that is defined as focusViewId in the XML Menu Model file.
Here are the steps to implement this technique:
1. Create a subclass of org.apache.myfaces.trinidad.model.XMLMenuModel and override method getFocusRowKey as follows:
public Object getFocusRowKey()
// first check whether default behavior results in focus of some menu item
Object focusRowKey = super.getFocusRowKey();
// check whether there is a menu mapping for the current viewId
Map viewIdMapping = getViewIdMapping();
String viewId = FacesContext.getCurrentInstance().getViewRoot().getViewId();
if (viewIdMapping!=null && viewIdMapping.get(viewId)!=null)
String mappedViewId = (String) viewIdMapping.get(viewId);