rich:panelMenu loses layout/theme and gets dublicated
kapuzo May 11, 2011 6:35 AMHi,
I trying to build a rich:panelMenu, but it wont work.
At first a small sumary of my project:
I am building a little onlinestore, nothing complicated but only with JSF 2.0 it lokks like a boring HTML/PHP or wahtever Website. So I decided to use Richfaces, because of the additional components and the ajax support.
A page of my application contains a template and this template is made of some other template-pages. So that I have got a default-remplate which includes a header, menu, linklist and a footer. The content is a ui:insert so that every page can define its content. In the menu-template I want the panelMenu to be.
default.xhtml (main-template)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:rich="http://richfaces.org/rich"
xmlns:a4j="http://richfaces.org/a4j">
<h:head>
<title><ui:insert name="title">
<h:outputText value="#{labels.title_app}" />
</ui:insert>
</title>
<link href="#{request.contextPath}/css/layout.css" rel="stylesheet"
type="text/css" />
</h:head>
<h:body>
<f:view>
<h:panelGroup id="page" layout="block" styleClass="page">
<h:panelGroup id="header" layout="block" styleClass="header">
<ui:include src="header.xhtml" />
</h:panelGroup>
<h:panelGroup id="contentBackground" layout="block"
styleClass="contentBackground">
<h:panelGroup id="menu" layout="block" styleClass="menu">
<ui:include src="menu.xhtml" />
</h:panelGroup>
<h:panelGroup id="shopPathContainer" layout="block"
styleClass="shopPathContainer">
<h:outputText value="#{labels.current_position}: " />›
<ui:insert name="currentPosition" />
</h:panelGroup>
<h:panelGroup id="content" layout="block" styleClass="content">
<ui:insert name="content" />
</h:panelGroup>
<h:panelGroup id="links" layout="block" styleClass="links">
<ui:include src="links.xhtml" />
</h:panelGroup>
<h:panelGroup id="bottomSeparator" layout="block"
styleClass="bottomSeparator">
<h:panelGroup id="bottomSeparatorLeft" layout="block"
styleClass="bottomSeparatorLeft" />
<h:panelGroup id="bottomSeparatorContent" layout="block"
styleClass="bottomSeparatorContent" />
</h:panelGroup>
</h:panelGroup>
<h:panelGroup id="footer" layout="block" styleClass="footer">
<ui:include src="footer.xhtml" />
</h:panelGroup>
</h:panelGroup>
</f:view>
</h:body>
</html>
menu.xhtml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:rich="http://richfaces.org/rich"
xmlns:a4j="http://richfaces.org/a4j">
<h:form id="menuForm">
<rich:panelMenu binding="#{menuBean.panelMenu}" activeItem="#{menuBean.activeItem}"
id="menu" style="width:158px"
itemMode="ajax" groupMode="ajax"
groupExpandedLeftIcon="triangleDown"
groupCollapsedLeftIcon="triangle"
topGroupExpandedLeftIcon="triangleDown"
topGroupCollapsedLeftIcon="triangle"
itemLeftIcon="grid">
<rich:panelMenuGroup id="ID1" label="Group 1" actionListener="#{menuBean.changeActiveMenuItem}" action="#{...}">
<rich:panelMenuItem id="ID2" label="Item 1.1" actionListener="#{menuBean.changeActiveMenuItem}" action="#{...}" />
<rich:panelMenuItem id="ID3" label="Item 1.2" actionListener="#{menuBean.changeActiveMenuItem}" action="#{...}" />
<rich:panelMenuItem id="ID4" label="Item 1.3" actionListener="#{menuBean.changeActiveMenuItem}" action="#{...}" />
</rich:panelMenuGroup>
<rich:panelMenuGroup id="ID5" label="Group 2" actionListener="#{menuBean.changeActiveMenuItem}" action="#{...}">
<rich:panelMenuItem id="ID6" label="Item 1.1" actionListener="#{menuBean.changeActiveMenuItem}" action="#{...}" />
<rich:panelMenuItem id="ID7" label="Item 1.2" actionListener="#{menuBean.changeActiveMenuItem}" action="#{...}" />
<rich:panelMenuItem id="ID8" label="Item 1.3" actionListener="#{menuBean.changeActiveMenuItem}" action="#{...}" />
</rich:panelMenuGroup>
</rich:panelMenu>
</h:form>
</ui:composition>
For exmaple my index.xhtml, which is the mainpage of the application looks like:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition template="../templates/default.xhtml"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:rich="http://richfaces.org/rich"
xmlns:a4j="http://richfaces.org/a4j">
<ui:define name="currentPosition">
<h:outputText value="#{labels.title_main}" />
</ui:define>
<ui:define name="content">
<h1>
<h:outputText value="#{labels.welcome}" />
</h1>
</ui:define>
</ui:composition>
login.xhtml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition template="../templates/default.xhtml"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets">
<ui:define name="currentPosition">
<h:outputText value="#{labels.title_login}" />
</ui:define>
<ui:define name="content">
<h1>
<h:outputText value="#{labels.title_login}" />
</h1>
<h:panelGroup id="centerBox" layout="block" styleClass="centerBox">
<h:panelGrid id="loginGrid" columns="2">
<h:outputLabel value="#{labels.username}:" for="username"
styleClass="gridLeft" />
<h:panelGroup id="usernameGroup" layout="block">
<h:message for="username" showDetail="true" showSummary="false"
styleClass="message small" />
<h:inputText id="username" binding="#{loginBean.usernameField}"
value="#{loginBean.username}" size="15" required="true"
requiredMessage="#{notifications.required}" />
</h:panelGroup>
<h:outputLabel value="#{labels.password}:" for="password"
styleClass="gridLeft" />
<h:panelGroup id="passwordGroup" layout="block">
<h:message for="password" showDetail="true" showSummary="false"
styleClass="message small" />
<h:inputSecret id="password" binding="#{loginBean.passwordField}"
value="#{loginBean.password}" size="15" required="true"
requiredMessage="#{notifications.required}" />
</h:panelGroup>
</h:panelGrid>
</h:panelGroup>
</ui:define>
</ui:composition>
The menu uses the ManagedBean MenuBean. I abbreviated the class a bit:
@ManagedBean
@SessionScoped
public class MenuBean implements Serializable {
private static final long serialVersionUID = 6047892824472925159L;
private static Logger log = Logger.getLogger(MenuBean.class.toString());
@EJB
private ProductService productService;
private List<Category> rootCategories = new ArrayList<Category>();
private List<AbstractPanelMenuItem> menuItems = new ArrayList<AbstractPanelMenuItem>();
private UIPanelMenu panelMenu;
private String activeItem;
@PostConstruct
public void init() {
//Getting the Categories from the EJB and build the UIPanelMenu
//Its not used in the current version
}
private void createMenu(Category c, UIComponent parent) {
//The MenuBuilding-Method, not used yet
}
// Getter and Setter for the other variables......
public UIPanelMenu getPanelMenu() {
// retuns on the first call null, but I did not see any difference if I create a new Object or the context does it.
return panelMenu;
}
public void setPanelMenu(UIPanelMenu panelMenu) {
this.panelMenu = panelMenu;
}
public void setActiveItem(String activeItem) {
this.activeItem = activeItem;
}
public String getActiveItem() {
return activeItem;
}
public void changeActiveMenuItem(ActionEvent event) {
this.updateActiveItem(event.getComponent());
}
private void updateActiveItem(UIComponent comp) {
if (comp != null) {
String tmp = this.getComponentID(comp.getClientId());
if (comp instanceof UIPanelMenuGroup && tmp.equals(activeItem)) {
activeItem = null;
} else {
activeItem = tmp;
}
} else {
activeItem = null;
}
}
private String getComponentID(String id) {
return id.substring(id.indexOf(":") + 1, id.length());
}
public String navigate() {
log.info("Navigating to : " + activeItem);
return NavigationUtil.INDEX;
}
}
Finally the web.xml. That coulb be the troublemaker, because of a lot testing and changing.
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<display-name>onlinestore</display-name>
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.jsf</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
<context-param>
<param-name>javax.faces.DEFAULT_SUFFIX</param-name>
<param-value>.xhtml</param-value>
</context-param>
<context-param>
<param-name>javax.faces.PROJECT_STAGE</param-name>
<param-value>Development</param-value>
</context-param>
<context-param>
<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
<param-value>server</param-value>
</context-param>
<context-param>
<param-name>org.richfaces.SKIN</param-name>
<param-value>DEFAULT</param-value>
</context-param>
</web-app>
These are the components that with which I got some trouble.
I am using as developing environment:
Eclipse EE 3.6 with JBossTools
Glassfish 3.1 Full
Mojarra JSF Impl which comes with Glassfish, not sure what version it is
Richfaces 4.0.0 Final, with additional libs:
richfaces-components-api-4.0.0.Final
richfaces-components-ui-4.0.0.Final
richfaces-core-api-4.0.0.Final
richfaces-core-impl-4.0.0.Final
cssparser-0.9.5
guava-r09
guava-r09-gwt
xml-apis
xml-apis-ext
Now to the problems:
I am trying to build a rich:panelMenu in a ManagedBean, which is SessionScoped. But as soon as I bind that rich:panelMenu from my JSF-page to a UIPanelMenu in my BackingBean the menu loses its theming. Or, to be more precise, it still has the style-tags but it does not show those styles.
Probably it is easier for you to understand, so I got two images of that behaviour.
Expected | What happened |
---|---|
On the first pageload the menu has its theming, but after a page-reload or a menuAction the theming is gone and the items are no langer "clickable". If I add a rich:panelMenu to that page and dont bind it, the menu is shown as I would expect it and works fine.
That is my first problem.
Now to the second one:
It also caused by the binding. Without binding there is no problem.
If I change the page from index.jsf to login.jsf, the menu is added twice and I got a java.lang.IllegalStateException that says:
Component-ID menuForm:ID1 is already on that View. (Sorry for that but the console output is not in english on my pc)
at com.sun.faces.util.Util.checkIdUniqueness(Util.java:821)
at com.sun.faces.util.Util.checkIdUniqueness(Util.java:805)
at com.sun.faces.util.Util.checkIdUniqueness(Util.java:805)
at com.sun.faces.util.Util.checkIdUniqueness(Util.java:805)
at com.sun.faces.util.Util.checkIdUniqueness(Util.java:805)
at com.sun.faces.util.Util.checkIdUniqueness(Util.java:805)
at com.sun.faces.util.Util.checkIdUniqueness(Util.java:805)
at com.sun.faces.application.view.StateManagementStrategyImpl.saveView(StateManagementStrategyImpl.java:140)
at com.sun.faces.application.StateManagerImpl.saveView(StateManagerImpl.java:133)
at com.sun.faces.application.view.WriteBehindStateWriter.flushToWriter(WriteBehindStateWriter.java:225)
at com.sun.faces.application.view.FaceletViewHandlingStrategy.renderView(FaceletViewHandlingStrategy.java:418)
at com.sun.faces.application.view.MultiViewHandler.renderView(MultiViewHandler.java:131)
at javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:288)
at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:121)
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:139)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:410)
at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1534)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:281)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:655)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:595)
at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:98)
at com.sun.enterprise.web.PESessionLockingStandardPipeline.invoke(PESessionLockingStandardPipeline.java:91)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:162)
at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:326)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:227)
at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:170)
at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:822)
at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:719)
at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1013)
at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:225)
at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104)
at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90)
at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79)
at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54)
at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59)
at com.sun.grizzly.ContextTask.run(ContextTask.java:71)
at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532)
at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513)
at java.lang.Thread.run(Thread.java:662)
Puh, that was a long way to go .
But now to my Question:
1. Why is the rich.panelMenu losing the theming or why is the theme no longer shown?
2. Why is the context trying to add the menu twice? What can I do to prevent that to happen?
Would be very nice if someone knows a solution for my problems, because I did not get any ideas after searching for three days to handle these problems.