Typical Web applications contain some form of left navigation bar. This page describes how to create a simple tree like collapsible navigation bar using Apache MyFaces Tobago.
Requirements
- Maven installed and configured
- Successful completion of a Hello World Application (my previous post)
At this time please complete a simple Hello World application (previous link) before proceeding…
For the site navigation we will use the tc:tree element to display a collapsible table.
Implementing the Model
The code listed below sets up a static Tree Structure that represents the left navigation bar. Each tree element will specify the key and the “outcome”. The key is used to find the Text to display for that item. And the “outcome” will be used by JSF to identify what page to forward the request to.
package com.test;
import java.util.Enumeration;
import javax.faces.context.FacesContext;
import javax.swing.tree.DefaultMutableTreeNode;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.myfaces.tobago.context.ResourceManagerUtil;
import org.apache.myfaces.tobago.model.TreeState;
/**
* The following constructs a very basic static navigation bar.
*/
public class Navigation {
private static final Log LOG = LogFactory.getLog(Navigation.class);
private DefaultMutableTreeNode tree;
private TreeState state;
public Navigation() {
tree = new DefaultMutableTreeNode(new Node("test", "Root", null));
DefaultMutableTreeNode home = new DefaultMutableTreeNode(new Node("test", "home", "pages/home"));
DefaultMutableTreeNode products = new DefaultMutableTreeNode(new Node("test", "products", "pages/products"));
DefaultMutableTreeNode portableAudio = new DefaultMutableTreeNode(new Node("test", "portable_audio", "pages/portable_audio"));
portableAudio.add(new DefaultMutableTreeNode(new Node("test", "cd", "pages/cd")));
portableAudio.add(new DefaultMutableTreeNode(new Node("test", "mp3", "pages/mp3")));
DefaultMutableTreeNode books = new DefaultMutableTreeNode(new Node("test", "books", "pages/books"));
DefaultMutableTreeNode newReleases = new DefaultMutableTreeNode(new Node("test", "new_releases", "pages/new_releases"));
newReleases.add(new DefaultMutableTreeNode(new Node("test", "action_adventure","pages/action_advendure")));
books.add(newReleases);
products.add(portableAudio);
products.add(books);
tree.add(home);
tree.add(products);
state = new TreeState();
state.expand(tree, 1);
state.setMarker(home);
}
public String navigate() {
Node selected = (Node) state.getMarker().getUserObject();
return selected.getOutcome();
}
public void updateMarker(String viewId) {
Enumeration enumeration = tree.depthFirstEnumeration();
while (enumeration.hasMoreElements()) {
DefaultMutableTreeNode maybeMarker = ((DefaultMutableTreeNode) enumeration.nextElement());
Node node = (Node) maybeMarker.getUserObject();
if (node.getOutcome() != null && viewId.contains(node.getOutcome())) {
state.setMarker(maybeMarker);
break;
}
}
}
public DefaultMutableTreeNode getTree() {
return tree;
}
public void setTree(DefaultMutableTreeNode tree) {
this.tree = tree;
}
public TreeState getState() {
return state;
}
public void setState(TreeState state) {
this.state = state;
}
public String gotoFirst() {
DefaultMutableTreeNode first = tree.getNextNode();
state.setMarker(first);
return ((Node) first.getUserObject()).getOutcome();
}
public String gotoPrevious() {
DefaultMutableTreeNode previousNode = state.getMarker().getPreviousNode();
if (previousNode != null) {
state.setMarker(previousNode);
return ((Node) previousNode.getUserObject()).getOutcome();
}
return null;
}
public String gotoNext() {
DefaultMutableTreeNode nextNode = state.getMarker().getNextNode();
if (nextNode != null) {
state.setMarker(nextNode);
return ((Node) nextNode.getUserObject()).getOutcome();
}
return null;
}
public boolean isFirst() {
return state.getMarker().getPreviousNode().isRoot();
}
public boolean isLast() {
return state.getMarker().getNextNode() == null;
}
public static class Node {
private String title;
private String id;
private String outcome;
public Node(String resourceBundle, String key, String outcome) {
this.title = ResourceManagerUtil.getProperty(
FacesContext.getCurrentInstance(), resourceBundle, key);
this.id = key;
this.outcome = outcome;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getOutcome() {
return outcome;
}
public void setOutcome(String outcome) {
this.outcome = outcome;
}
}
}
Create the resource bundle file
need to create a resource bundle file in
src/main/webapp/tobago-resource/html/standard/standard/property/test.properties.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"> <properties> <entry key="neeraj_name">Neeraj Verma</entry> <entry key="home">Home</entry> <entry key="products">Products</entry> <entry key="portable_audio">Portable Audio</entry> <entry key="cd">CD</entry> <entry key="mp3">MP3</entry> <entry key="books">Books</entry> <entry key="new_releases">New Releases</entry> <entry key="action_adventure">Action Adventure</entry> </properties>
Modify Navigation Rules
The next step is to setup the navigation rules. Make the changes highlighted below to the faces-config.xml file. The navigation rules section describes how to forward the user to the next page when they click on the navigation bar. The navigation bar contains the “outcome” for each entry.
src/main/webapp/WEB-INF/faces-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE faces-config PUBLIC
"-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.1//EN"
"http://java.sun.com/dtd/web-facesconfig_1_1.dtd">
<faces-config>
<application>
<locale-config>
<default-locale>en</default-locale>
<supported-locale>de</supported-locale>
<supported-locale>de_DE</supported-locale>
<supported-locale>de_AT</supported-locale>
<supported-locale>de_CH</supported-locale>
</locale-config>
</application>
<navigation-rule>
<navigation-case>
<from-outcome>pages/home</from-outcome>
<to-view-id>pages/home.jsp</to-view-id>
</navigation-case>
<navigation-case>
<from-outcome>pages/products</from-outcome>
<to-view-id>pages/products.jsp</to-view-id>
</navigation-case>
<navigation-case>
<from-outcome>pages/portable_audio</from-outcome>
<to-view-id>pages/portable_audio.jsp</to-view-id>
</navigation-case>
<navigation-case>
<from-outcome>pages/cd</from-outcome>
<to-view-id>pages/cd.jsp</to-view-id>
</navigation-case>
</navigation-rule>
<managed-bean>
<managed-bean-name>navigation</managed-bean-name>
<managed-bean-class>com.test.Navigation</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
</faces-config>
Implement the Target Pages
As you can see above each “outcome” leads to a different jsp page. For that reason please take the time to create the 4 jsp’s listed above
- src/main/webapp/pages/home.jsp
- src/main/webapp/pages/products.jsp
- src/main/webapp/pages/portable_audio.jsp
- src/main/webapp/pages/cd.jsp
You can put anything you want in those JSP’s “Test 123 [jsp name]” whatever…
Implement the page
Modify the helloWorld.jsp page to look like this: The lines highlighted below are the differences from the file posted in my previous article.
<%@ taglib uri="http://myfaces.apache.org/tobago/component" prefix="tc" %>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<tc:loadBundle basename="test" var="testBundle"/>
<f:view>
<tc:page>
<f:facet name="layout">
<tc:gridLayout/>
</f:facet>
<tc:tree value="#{navigation.tree}"
mode="menu"
id="nav"
nameReference="userObject.title"
idReference="userObject.id"
tipReference="userObject.title"
state="#{navigation.state}"
showIcons="false"
showJunctions="false"
showRoot="false">
<f:facet name="treeNodeCommand">
<tc:link action="#{navigation.navigate}" immediate="true"/>
</f:facet>
</tc:tree>
</tc:page>
</f:view>
Test the Application
Start the application in jetty.
mvn jetty:run
Navigate to http://localhost:8080/
You should see a navigation menu smack in top of the html page. It will most likely take up the whole browser window. Next we need to create a layout and place this navigation bar on the left of the page. Please read my next article where I describe how this is done.
That’s All for now…