Foundation
Project Documentation

Introduction

Pages are not written in isolation, an application consists of many pages. Often these pages are organized in a tree, and the user drills down into the tree to access more specific information. The figure below represents a tree of pages.

Depth 0:                            a1                         a2        a3    a4
                            /                \                /  \
Depth 1:                a1b1                  a1b2         a2b1  a2b2
                     /        \             /      \
Depth 2:          a1b1c1    a1b1c2    a1b2c1  a1b2c2
                 /      \
Depth 3:    a1b1c1d1  a1b1c2d1
Figure 1


Here's an example at the kind of navigation rules you might find in faces-config for the group of pages above.
<navigation-rule>
    <navigation-case>
      <from-outcome>guide.navigationModel_root</from-outcome>
      <to-view-id>/components/navmodel/page.jspx</to-view-id>
      <redirect/>
    </navigation-case>
    <navigation-case>
      <from-outcome>guide.navigationModel_a1</from-outcome>
      <to-view-id>/components/navmodel/page_a1.jspx</to-view-id>
      <redirect/>
    </navigation-case>
    <navigation-case>
      <from-outcome>guide.navigationModel_a2</from-outcome>
      <to-view-id>/components/navmodel/page_a2.jspx</to-view-id>
      <redirect/>
    </navigation-case>
    <navigation-case>
      <from-outcome>guide.navigationModel_a3</from-outcome>
      <to-view-id>/components/navmodel/page_a3.jspx</to-view-id>
      <redirect/>
    </navigation-case>
    <navigation-case>
      <from-outcome>guide.navigationModel_a4</from-outcome>
      <to-view-id>/components/navmodel/page_a4.jspx</to-view-id>
      <redirect/>
    </navigation-case>
     <navigation-case>
      <from-outcome>guide.navigationModel_a1b1</from-outcome>
      <to-view-id>/components/navmodel/page_a1b1.jspx</to-view-id>
      <redirect/>
    </navigation-case>
     <navigation-case>
      <from-outcome>guide.navigationModel_a1b2</from-outcome>
      <to-view-id>/components/navmodel/page_a1b2.jspx</to-view-id>
      <redirect/>
    </navigation-case>
     <navigation-case>
      <from-outcome>guide.navigationModel_a2b1</from-outcome>
      <to-view-id>/components/navmodel/page_a2b1.jspx</to-view-id>
      <redirect/>
    </navigation-case>
     <navigation-case>
      <from-outcome>guide.navigationModel_a2b2</from-outcome>
      <to-view-id>/components/navmodel/page_a2b2.jspx</to-view-id>
      <redirect/>
    </navigation-case>
     <navigation-case>
      <from-outcome>guide.navigationModel_a1b1c1</from-outcome>
      <to-view-id>/components/navmodel/page_a1b1c1.jspx</to-view-id>
      <redirect/>
    </navigation-case>
     <navigation-case>
      <from-outcome>guide.navigationModel_a1b1c2</from-outcome>
      <to-view-id>/components/navmodel/page_a1b1c2.jspx</to-view-id>
      <redirect/>
    </navigation-case>
     <navigation-case>
      <from-outcome>guide.navigationModel_a1b2c1</from-outcome>
      <to-view-id>/components/navmodel/page_a1b2c1.jspx</to-view-id>
      <redirect/>
    </navigation-case>
     <navigation-case>
      <from-outcome>guide.navigationModel_a1b2c2</from-outcome>
      <to-view-id>/components/navmodel/page_a1b2c2.jspx</to-view-id>
      <redirect/>
    </navigation-case>
     <navigation-case>
      <from-outcome>guide.navigationModel_a1b1c1d1</from-outcome>
      <to-view-id>/components/navmodel/page_a1b1c1d1.jspx</to-view-id>
      <redirect/>
    </navigation-case>
     <navigation-case>
      <from-outcome>guide.navigationModel_a1b1c2d1</from-outcome>
      <to-view-id>/components/navmodel/page_a1b1c2d1.jspx</to-view-id>
      <redirect/>
    </navigation-case>
  </navigation-rule>


So what components should be used in Apache Trinidad to achieve the layout above? There are multiple options: use panelPage and navigation components that take a series of commandNavigationItem children, use panelPage and navigation components that use a navigation model and a single commandNavigationItem child in the nodeStamp facet, or use the page component with a navigation model and a single commandNavigationItem child in the nodeStamp facet. These techniques are discussed in this chapter.

Navigation Components and Children

The panelPage component organizes the content of an entire page. The panelPage has multiple facets which are used to render the navigation areas of the page (among other navigation-related areas). The navigation components then go inside these facets. The "intuitive" way to build up the navigation components is to just add children to the navigation components. The example that follows should produce the same output as seen in figure 2.

<?xml version="1.0" encoding="iso-8859-1" standalone="yes" ?>
<jsp:root version="1.2"
  xmlns:jsp="http://java.sun.com/JSP/Page"
  xmlns:f="http://java.sun.com/jsf/core"
  xmlns:tr="http://myfaces.apache.org/">
  <jsp:directive.page contentType="text/html;charset=utf-8"/>
  <f:view>
    <tr:document title="MenuModel Demo" maximized="true">
      <tr:form>
        <tr:panelPage>
          <f:facet name="branding">
            <tr:panelGroup layout="horizontal">
              <tr:objectIcon name="logo"/>
              <tr:outputText value="MenuModel Demo"/>
            </tr:panelGroup>
          </f:facet>
          <f:facet name="navigationGlobal">
            <tr:navigationLevel>
              <tr:commandNavigationItem text="a1" action="guide.navigationModel_a1"
                selected="true"/>
              <tr:commandNavigationItem text="a2" action="guide.navigationModel_a2"/>
              <tr:commandNavigationItem text="a3" action="guide.navigationModel_a3"/>
              <tr:commandNavigationItem text="a4" action="guide.navigationModel_a4"/>
            </tr:navigationLevel>
          </f:facet>
          <f:facet name="navigation1">
            <tr:navigationLevel>
              <tr:commandNavigationItem text="a1b1" action="guide.navigationModel_a1b1"/>
              <tr:commandNavigationItem text="a1b2" action="guide.navigationModel_a1b2"
                selected="true"/>
            </tr:navigationLevel>
          </f:facet>
          <f:facet name="navigation2">
            <tr:navigationLevel>
              <tr:commandNavigationItem text="a1b2c1" action="guide.navigationModel_a1b2c1"
                selected="true"/>
              <tr:commandNavigationItem text="a1b2c2" action="guide.navigationModel_a1b2c2"/>
            </tr:navigationLevel>
          </f:facet>
          <f:facet name="location">
            <tr:navigationPath>
              <tr:commandNavigationItem text="a1" action="guide.navigationModel_a1"/>
              <tr:commandNavigationItem text="a1b2" action="guide.navigationModel_a1b2"/>
              <tr:commandNavigationItem text="a1b2c1" action="guide.navigationModel_a1b2c1"/>
            </tr:navigationPath>
          </f:facet>
        </tr:panelPage>
      </tr:form>
    </tr:document>
  </f:view>
</jsp:root>

Navigation Model

NOTE: Work on modeling navigation continues and it is very possible that there will be changes in a future release.

So what is wrong with the panelPage approach described above? It's simple and easy to understand and it works. The problem is that it's not easy to get things right. For example the page author must take care to show the correct nodes as "selected". It's also not easily maintained. What if a page is moved from one place to another in the tree (see figure 1)?

What is needed is a model object that knows the application hierarchy and also knows how to say what is the current "focus path" in that hierarchy. The MenuModel class was created for this purpose. MenuModel extends TreeModel, so if you are not familiar with the model for the tree it is important that you first read the tree chapter.

The navigation model knows how to go from the current viewId to the focus path. For example if I am on page a1b2c1, a call to getFocusRowKey() will return the focus path of a1, a1b2, and a1b2c1.

Notice that the navigationModel has no special knowledge of page navigation and places no requirements on the nodes that go into the tree. The components that take a navigationModel use a commandNavigationItem component to stamp out the data in the tree. The default actionListener mechanism is used for page navigation.

The following example shows how a navigation model can be created in faces-config. The DemoNavigationItem class is a bean. The TreeModelAdapter class creates a ChildPropertyTreeModel instance, and the MenuModelAdapter creates a ViewIdPropertyMenuModel instance which can be retrieved by calling MenuModelAdapter.getModel(). Please see the javadoc for more information on ChildPropertyTreeModel and ViewIdPropertyMenuModel.

Skip to end of faces-config fragment.

   <!-- create the navigationModel nodes -->

   <managed-bean>
    <managed-bean-name>navItem_a1b1c1d1</managed-bean-name>
    <managed-bean-class>org.apache.myfaces.trinidaddemo.nav.DemoNavigationItem</managed-bean-class>
    <managed-bean-scope>none</managed-bean-scope>
    <managed-property>
      <property-name>label</property-name>
      <value>a1b1c1d1</value>
    </managed-property>
    <managed-property>
      <property-name>viewId</property-name>
      <value>/components/navmodel/page_a1b1c1d1.jspx</value>
    </managed-property>
    <managed-property>
      <property-name>outcome</property-name>
      <value>guide.navigationModel_a1b1c1d1</value>
    </managed-property>
  </managed-bean>

  <managed-bean>
    <managed-bean-name>navItem_a1b1c2d1</managed-bean-name>
    <managed-bean-class>org.apache.myfaces.trinidaddemo.nav.DemoNavigationItem</managed-bean-class>
    <managed-bean-scope>none</managed-bean-scope>
    <managed-property>
      <property-name>label</property-name>
      <value>a1b1c2d1</value>
    </managed-property>
    <managed-property>
      <property-name>viewId</property-name>
      <value>/components/navmodel/page_a1b1c2d1.jspx</value>
    </managed-property>
    <managed-property>
      <property-name>outcome</property-name>
      <value>guide.navigationModel_a1b1c2d1</value>
    </managed-property>
  </managed-bean>

   <managed-bean>
    <managed-bean-name>navItem_a1b1c1</managed-bean-name>
    <managed-bean-class>org.apache.myfaces.trinidaddemo.nav.DemoNavigationItem</managed-bean-class>
    <managed-bean-scope>none</managed-bean-scope>
    <managed-property>
      <property-name>children</property-name>
      <list-entries>
        <value-class>org.apache.myfaces.trinidaddemo.nav.DemoNavigationItem</value-class>
        <value>#{navItem_a1b1c1d1}</value>
      </list-entries>
    </managed-property>
    <managed-property>
      <property-name>label</property-name>
      <value>a1b1c1</value>
    </managed-property>
    <managed-property>
      <property-name>viewId</property-name>
      <value>/components/navmodel/page_a1b1c1.jspx</value>
    </managed-property>
    <managed-property>
      <property-name>outcome</property-name>
      <value>guide.navigationModel_a1b1c1</value>
    </managed-property>
  </managed-bean>

   <managed-bean>
    <managed-bean-name>navItem_a1b1c2</managed-bean-name>
    <managed-bean-class>org.apache.myfaces.trinidaddemo.nav.DemoNavigationItem</managed-bean-class>
    <managed-bean-scope>none</managed-bean-scope>
    <managed-property>
      <property-name>children</property-name>
      <list-entries>
        <value-class>org.apache.myfaces.trinidaddemo.nav.DemoNavigationItem</value-class>
        <value>#{navItem_a1b1c2d1}</value>
      </list-entries>
    </managed-property>
    <managed-property>
      <property-name>label</property-name>
      <value>a1b1c2</value>
    </managed-property>
    <managed-property>
      <property-name>viewId</property-name>
      <value>/components/navmodel/page_a1b1c2.jspx</value>
    </managed-property>
    <managed-property>
      <property-name>outcome</property-name>
      <value>guide.navigationModel_a1b1c2</value>
    </managed-property>
  </managed-bean>

   <managed-bean>
    <managed-bean-name>navItem_a1b2c1</managed-bean-name>
    <managed-bean-class>org.apache.myfaces.trinidaddemo.nav.DemoNavigationItem</managed-bean-class>
    <managed-bean-scope>none</managed-bean-scope>
    <managed-property>
      <property-name>label</property-name>
      <value>a1b2c1</value>
    </managed-property>
    <managed-property>
      <property-name>viewId</property-name>
      <value>/components/navmodel/page_a1b2c1.jspx</value>
    </managed-property>
    <managed-property>
      <property-name>outcome</property-name>
      <value>guide.navigationModel_a1b2c1</value>
    </managed-property>
  </managed-bean>

   <managed-bean>
    <managed-bean-name>navItem_a1b2c2</managed-bean-name>
    <managed-bean-class>org.apache.myfaces.trinidaddemo.nav.DemoNavigationItem</managed-bean-class>
    <managed-bean-scope>none</managed-bean-scope>
    <managed-property>
      <property-name>label</property-name>
      <value>a1b2c2</value>
    </managed-property>
    <managed-property>
      <property-name>viewId</property-name>
      <value>/components/navmodel/page_a1b2c2.jspx</value>
    </managed-property>
    <managed-property>
      <property-name>outcome</property-name>
      <value>guide.navigationModel_a1b2c2</value>
    </managed-property>
  </managed-bean>

   <managed-bean>
    <managed-bean-name>navItem_a1b1</managed-bean-name>
    <managed-bean-class>org.apache.myfaces.trinidaddemo.nav.DemoNavigationItem</managed-bean-class>
    <managed-bean-scope>none</managed-bean-scope>
    <managed-property>
      <property-name>children</property-name>
      <list-entries>
        <value-class>org.apache.myfaces.trinidaddemo.nav.DemoNavigationItem</value-class>
        <value>#{navItem_a1b1c1}</value>
        <value>#{navItem_a1b1c2}</value>
      </list-entries>
    </managed-property>
    <managed-property>
      <property-name>label</property-name>
      <value>a1b1</value>
    </managed-property>
    <managed-property>
      <property-name>viewId</property-name>
      <value>/components/navmodel/page_a1b1.jspx</value>
    </managed-property>
    <managed-property>
      <property-name>outcome</property-name>
      <value>guide.navigationModel_a1b1</value>
    </managed-property>
  </managed-bean>

   <managed-bean>
    <managed-bean-name>navItem_a1b2</managed-bean-name>
    <managed-bean-class>org.apache.myfaces.trinidaddemo.nav.DemoNavigationItem</managed-bean-class>
    <managed-bean-scope>none</managed-bean-scope>
    <managed-property>
      <property-name>children</property-name>
      <list-entries>
        <value-class>org.apache.myfaces.trinidaddemo.nav.DemoNavigationItem</value-class>
        <value>#{navItem_a1b2c1}</value>
        <value>#{navItem_a1b2c2}</value>
      </list-entries>
    </managed-property>
    <managed-property>
      <property-name>label</property-name>
      <value>a1b2</value>
    </managed-property>
    <managed-property>
      <property-name>viewId</property-name>
      <value>/components/navmodel/page_a1b2.jspx</value>
    </managed-property>
    <managed-property>
      <property-name>outcome</property-name>
      <value>guide.navigationModel_a1b2</value>
    </managed-property>
  </managed-bean>

   <managed-bean>
    <managed-bean-name>navItem_a2b1</managed-bean-name>
    <managed-bean-class>org.apache.myfaces.trinidaddemo.nav.DemoNavigationItem</managed-bean-class>
    <managed-bean-scope>none</managed-bean-scope>
    <managed-property>
      <property-name>label</property-name>
      <value>a2b1</value>
    </managed-property>
    <managed-property>
      <property-name>viewId</property-name>
      <value>/components/navmodel/page_a2b1.jspx</value>
    </managed-property>
    <managed-property>
      <property-name>outcome</property-name>
      <value>guide.navigationModel_a2b1</value>
    </managed-property>
  </managed-bean>


   <managed-bean>
    <managed-bean-name>navItem_a2b2</managed-bean-name>
    <managed-bean-class>org.apache.myfaces.trinidaddemo.nav.DemoNavigationItem</managed-bean-class>
    <managed-bean-scope>none</managed-bean-scope>
    <managed-property>
      <property-name>label</property-name>
      <value>a2b2</value>
    </managed-property>
    <managed-property>
      <property-name>viewId</property-name>
      <value>/components/navmodel/page_a2b2.jspx</value>
    </managed-property>
    <managed-property>
      <property-name>outcome</property-name>
      <value>guide.navigationModel_a2b2</value>
    </managed-property>
  </managed-bean>

  <managed-bean>
    <managed-bean-name>navItem_a1</managed-bean-name>
    <managed-bean-class>org.apache.myfaces.trinidaddemo.nav.DemoNavigationItem</managed-bean-class>
    <managed-bean-scope>none</managed-bean-scope>
    <managed-property>
      <property-name>children</property-name>
      <list-entries>
        <value-class>org.apache.myfaces.trinidaddemo.nav.DemoNavigationItem</value-class>
        <value>#{navItem_a1b1}</value>
        <value>#{navItem_a1b2}</value>
      </list-entries>
    </managed-property>
    <managed-property>
      <property-name>label</property-name>
      <value>a1</value>
    </managed-property>
    <!-- For a one-and-only-one selected navigation item behavior, remove the
         "viewId" declaration and modify the "outcome" declaration so that it
         takes the user to a deeper page, e.g. guide.navigationModel_a1b2.
         Doing this eliminates the page_a1.jspx, so it could be deleted too.
         This would also need to be done for all of the other navigation item
         definitions (i.e. not just "navItem_a1"). -->
    <managed-property>
      <property-name>viewId</property-name>
      <value>/components/navmodel/page_a1.jspx</value>
    </managed-property>
    <managed-property>
      <property-name>outcome</property-name>
      <value>guide.navigationModel_a1</value>
    </managed-property>
  </managed-bean>

  <managed-bean>
    <managed-bean-name>navItem_a2</managed-bean-name>
    <managed-bean-class>org.apache.myfaces.trinidaddemo.nav.DemoNavigationItem</managed-bean-class>
    <managed-bean-scope>none</managed-bean-scope>
    <managed-property>
      <property-name>children</property-name>
      <list-entries>
        <value-class>org.apache.myfaces.trinidaddemo.nav.DemoNavigationItem</value-class>
        <value>#{navItem_a2b1}</value>
        <value>#{navItem_a2b2}</value>
      </list-entries>
    </managed-property>
    <managed-property>
      <property-name>label</property-name>
      <value>a2</value>
    </managed-property>
    <managed-property>
      <property-name>viewId</property-name>
      <value>/components/navmodel/page_a2.jspx</value>
    </managed-property>
    <managed-property>
      <property-name>outcome</property-name>
      <value>guide.navigationModel_a2</value>
    </managed-property>
  </managed-bean>

  <managed-bean>
    <managed-bean-name>navItem_a3</managed-bean-name>
    <managed-bean-class>org.apache.myfaces.trinidaddemo.nav.DemoNavigationItem</managed-bean-class>
    <managed-bean-scope>none</managed-bean-scope>
    <managed-property>
      <property-name>label</property-name>
      <value>a3</value>
    </managed-property>
    <managed-property>
      <property-name>viewId</property-name>
      <value>/components/navmodel/page_a3.jspx</value>
    </managed-property>
    <managed-property>
      <property-name>outcome</property-name>
      <value>guide.navigationModel_a3</value>
    </managed-property>
  </managed-bean>

 <managed-bean>
    <managed-bean-name>navItem_a4</managed-bean-name>
    <managed-bean-class>org.apache.myfaces.trinidaddemo.nav.DemoNavigationItem</managed-bean-class>
    <managed-bean-scope>none</managed-bean-scope>
    <managed-property>
      <property-name>label</property-name>
      <value>a4</value>
    </managed-property>
    <managed-property>
      <property-name>viewId</property-name>
      <value>/components/navmodel/page_a4.jspx</value>
    </managed-property>
    <managed-property>
      <property-name>outcome</property-name>
      <value>guide.navigationModel_a4</value>
    </managed-property>
  </managed-bean>

  <!-- create the treemodel -->
  
 <managed-bean>
    <managed-bean-name>navTreeList</managed-bean-name>
    <managed-bean-class>
       java.util.ArrayList
    </managed-bean-class>
    <managed-bean-scope>
       none
    </managed-bean-scope>
     <list-entries>
        <value-class>org.apache.myfaces.trinidaddemo.nav.DemoNavigationItem</value-class>
        <value>#{navItem_a1}</value>
        <value>#{navItem_a2}</value>
        <value>#{navItem_a3}</value>
        <value>#{navItem_a4}</value>
      </list-entries>
  </managed-bean>
  
  <managed-bean>
    <managed-bean-name>navTreeModel</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>#{navTreeList}</value>
    </managed-property>
  </managed-bean>

  <!-- create the navigationModel -->
  
  <managed-bean>
    <managed-bean-name>viewIdMenuModel</managed-bean-name>
    <managed-bean-class>org.apache.myfaces.trinidad.model.ViewIdPropertyMenuModel</managed-bean-class>
    <managed-bean-scope>none</managed-bean-scope>
    <managed-property>
      <property-name>viewIdProperty</property-name>
      <value>viewId</value>
    </managed-property>
    <managed-property>
      <property-name>wrappedData</property-name>
      <value>#{navTreeModel}</value>
    </managed-property>    
  </managed-bean>  
  
  <managed-bean>
    <managed-bean-name>navigationModel</managed-bean-name>
    <managed-bean-class>org.apache.myfaces.trinidaddemo.nav.MenuModelAdapter</managed-bean-class>
    <managed-bean-scope>session</managed-bean-scope>   
    <managed-property>
      <property-name>model</property-name>
      <value>#{viewIdMenuModel}</value>
    </managed-property>
    <managed-property>
      <property-name>aliasList</property-name>
      <list-entries>
        <value-class>java.lang.String</value-class>
        <value>/components/navmodel/page_p1.jspx</value>
        <value>#{navItem_a2b1.viewId}</value>
        <value>/components/navmodel/page_p2.jspx</value>
        <value>#{navItem_a2b1.viewId}</value>
        <value>/components/navmodel/page_p3.jspx</value>
        <value>#{navItem_a2b1.viewId}</value>
        <value>/components/navmodel/page_p4.jspx</value>
        <value>#{navItem_a2b1.viewId}</value>
      </list-entries>
    </managed-property>

  </managed-bean>

Navigation Components and the MenuModel

Note: In a subsequent release the use of the level and startLevel attributes will almost certainly be replaced with an el expression in the 'value' attribute.

As in the first example, we are still using the panelPage and navigation components, but in the example that follows we are binding the navigation components to a navigationModel. Notice it is the commandNavigationItem component stamp which renders the data in the node. The example that follows should produce the same output as seen in figure 2.

<?xml version="1.0" encoding="iso-8859-1" standalone="yes" ?>
<jsp:root version="1.2"
  xmlns:jsp="http://java.sun.com/JSP/Page"
  xmlns:f="http://java.sun.com/jsf/core"
  xmlns:tr="http://myfaces.apache.org/trinidad">
  <jsp:directive.page contentType="text/html;charset=utf-8"/>
  <f:view>
    <tr:document title="MenuModel Demo" maximized="true">
      <tr:form>
        <tr:panelPage>
          <f:facet name="branding">
            <tr:panelGroup layout="horizontal">
              <tr:objectIcon name="logo"/>
              <tr:outputText value="MenuModel Demo"/>
            </tr:panelGroup>
          </f:facet>
          <f:facet name="navigationGlobal">
            <tr:navigationLevel var="foo" value="#{navigationModel.model}">
              <f:facet name="nodeStamp">
                <tr:commandNavigationItem
                  text="#{foo.label}"
                  action="#{foo.getOutcome}"/>
              </f:facet>
            </tr:navigationLevel>
          </f:facet>
          <f:facet name="navigation1">
            <tr:navigationLevel var="foo" value="#{navigationModel.model}" level="1">
              <f:facet name="nodeStamp">
                <tr:commandNavigationItem
                  text="#{foo.label}"
                  action="#{foo.getOutcome}"/>
              </f:facet>
            </tr:navigationLevel>
          </f:facet>
          <f:facet name="navigation2">
            <tr:navigationLevel var="foo" value="#{navigationModel.model}" level="2">
              <f:facet name="nodeStamp">
                <tr:commandNavigationItem
                  text="#{foo.label}"
                  action="#{foo.getOutcome}"/>
              </f:facet>
            </tr:navigationLevel>
          </f:facet> 
          <f:facet name="navigation3">
            <tr:navigationLevel var="foo" value="#{navigationModel.model}" level="3">
              <f:facet name="nodeStamp">
                <tr:commandNavigationItem
                  text="#{foo.label}"
                  action="#{foo.getOutcome}"/>
              </f:facet>
            </tr:navigationLevel>
          </f:facet>
          <f:facet name="location">
            <tr:navigationPath var="foo" value="#{navigationModel.model}">
              <f:facet name="nodeStamp">
                <tr:commandNavigationItem
                  text="#{foo.label}"
                  action="#{foo.getOutcome}"/>
              </f:facet>
            </tr:navigationPath>
          </f:facet>
        </tr:panelPage>
      </tr:form>
    </tr:document>
  </f:view>
</jsp:root>

Page

Using the navigationModel with navigation components has made some things easier, but it hasn't solved all our problems. For example, if we were looking at page a1b1c1 instead of a1b2c1 (see figure 1), we should use a navigationTree in the navigation3 facet rather than a navigationLevel. If we were looking at page a1, we don't need anything at all in the navigation3 facet.

More importantly, what if we want to make a dramatic change the way navigation looks. Maybe we want the page component to render cascading popups, meaning list of items that drop down off of an item when you click it. Using the panelPage and navigation components ties you to specific renderers for the navigation components.

The page component is more flexible still, binding to a navigationModel and stamping out the navigation items. The advantages of using a page componenent are that the renderer could render the navigation items in many different ways, for example it could render the cascading popups described above. Also, the page author doesn't need to know anything about where this page is in the hierarchy of pages. To render a1b1c1 or a1 we would use the exact same syntax as below.

The example that follows should produce the same output as seen in figure 2.

<?xml version="1.0" encoding="iso-8859-1" standalone="yes" ?>
<jsp:root version="1.2"
  xmlns:jsp="http://java.sun.com/JSP/Page"
  xmlns:f="http://java.sun.com/jsf/core"
  xmlns:tr="http://myfaces.apache.org/trinidad">
  <jsp:directive.page contentType="text/html;charset=utf-8"/>
  <f:view>
    <tr:document title="MenuModel Demo" maximized="true">
      <tr:form>
        <tr:page>
          <f:facet name="branding">
            <tr:panelGroup layout="horizontal">
              <tr:objectIcon name="logo"/>
              <tr:outputText value="MenuModel Demo"/>
            </tr:panelGroup>
          </f:facet>
          <f:facet name="nodeStamp">
            <tr:commandNavigationItem
              text="#{foo.label}"
              action="#{foo.getOutcome}"/>
          </f:facet>
        </tr:page>
      </tr:form>
    </tr:document>
  </f:view>
</jsp:root>