ADF Faces 10.1.3: Dynamic Menus w/ ADF Regions
While developing my application I reused a number of pages for different pages flows for different user roles. This resulted in the need for different sub menus (aka "menu2" facet in <af:panelPage>).
The Approach
Instead of putting the sub menu in every page, I've chosen to use <af:region> to reduce the code and be more flexible during the design. This region uses a member of the application's state bean. (An implementation detail of my application - see the SRDemo for a similar approach to store context information). The region itself retrieves the menu context and decides which menu to display.Using a Region
Using a Region within a .jspx page is quite easy. Instead of your ADF Faces tags use the <af:region> tag to reference the specific region:<f:facet name="menu2">
<af:region id="menu2Region"
regionType="demo.regions.menu2">
<f:attribute name="create" value="false" />
</af:region>
</f:facet>
Define a Region Mapping
To use a region we must tell ADF Faces where to find the definition of the region. This will be done in the WEB-INF/region-metadata.xml file.<component>
<component-type>demo.regions.menu2</component-type>
<component-class>oracle.adf.view.faces.component.UIXRegion</component-class>
<component-extension>
<region-jsp-ui-def>/regions/subMenu.jspx</region-jsp-ui-def>
</component-extension>
<attribute>
<attribute-name>create</attribute-name>
<attribute-class>java.lang.String</attribute-class>
</attribute>
</component>
This example also shows that a region can have parameters (or attributes) that are used within the region definition. You see the usage of parameters above.
Define a Region
Finally we define the region in a separate file which contains the complete tags we'd like to use.<af:regionDef var="aParam"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:af="http://xmlns.oracle.com/adf/faces">
<!-- ... -->
</af:regionDef>
Don't forget to define the namespaces in the <af:regionDef> tag to make JDeveloper Code-Insight happy.
The Dynamic Region Content
Essentially, you put every tag you want to use within the <af:regionDef> tag. To add a bit dynamic for the context-based menu display, I've put the <af:switcher> around my different versions of the menus. Every possible case is wrapped by a normal JSF <f:facet> tag.<af:switcher defaultFacet="default"
facetName="#{userState.menuContext}">
<f:facet name="organisation">
<af:menuBar>
<af:commandMenuItem
text="#{res['page.organisation.create']}"
action="createOrganisation"
rendered="#{!userState.patientRole}"
immediate="true"
selected="#{aParam.create == 'true'}"/>
</af:menuBar>
</f:facet>
<!-- more facets here -->
</af:regionDef>
Please note, how I determine the current menu context from the application context bean with facetName="#{userState.menuContext}".
We also see how the parameters are used. As these are Strings we have to compare them with literal values.
Setting the Menu Context
When I change the main menu context, an action is called and sets the current menu context field in the application context bean. Here is a sample of the action:public String organisationAction() {
setMenuContext("organisation");
return "GlobalOrganisation";
}
Since the navigation rule for the menus is designed as a global outcome ("GlobalOrganisation"), I've placed this action in the application context bean, too.