Reputation: 8672
I have a page which takes a GET parameter, for example: /manageSquare.xhtml?squareName=foobar
. This page has a backing bean that is request scoped. To properly initialize the backing bean, the bean includes a initialize
method which will be called since the page includes a <f:metadata>
with an <f:viewParam>
and <f:event type="preRenderView ...>
. Sometimes the square does not exist, and some special error message will be shown. Therefore there is a <h:panelGroup rendered="#{squareBean.squareExist}">
element.
Now - the problem is that if I have a <h:commandButton>
element inside such a <h:panelGroup>
then whenever the form is submitted, only navigation takes place but the action method is never called! How can this be?
Here is some conceptual code (boiled down)
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:fn="http://java.sun.com/jsp/jstl/functions"
template="../template.xhtml">
<ui:param name="title" value="Square"/>
<f:metadata>
<f:viewParam name="squareName" value="#{manageSquareBean.squareName}"/>
<f:event type="preRenderView" listener="#{manageSquareBean.initialize}"/>
</f:metadata>
<ui:define name="content">
<h1>Manage square <h:outputText escape="true" value="#{manageSquareBean.squareName}"/></h1>
<h:panelGroup rendered="#{!manageSquareBean.squareExists}">
<span class="error">Square does not exist</span>
</h:panelGroup>
<h:panelGroup rendered="#{manageSquareBean.squareExists}">
<h:form>
<h:commandButton action="#{manageSquareBean.addUsersToSquare}" value="Add users">
<f:param name="squareName" value="#{manageSquareBean.squareName}"/>
</h:commandButton>
</h:form>
</h:panelGroup>
</ui:define>
</ui:composition>
and here is the a managedBean:
@RequestScoped
@ManagedBean
public class ManageSquareBean
{
private String squareName;
private boolean squareExists;
private List<String> usersToAdd;
public void initialize()
{
// Find out if squareName exists
squareExists = squareExists(squareName);
}
public String addUsersToSquare()
{
// Do something
}
// Getters and setters
}
I really do not understand why this is happening. Removing the <panelGroup>
and everything is fine. Also, it seems the squareName param is not sent forward when the commandButton is pressed.
Here is a person having the same problem. He solved it using JSTL instead of <panelGroup>
, but JSTL will run on build time which is before the initialize
method is called.
Please help, I have used many hours on this problem.
Upvotes: 1
Views: 2141
Reputation: 1108742
The rendered
attribute of the input and command component and all its parents is re-evaluated during the apply request values phase of the form submit. Since your bean is request scoped, a completely new bean is created upon the submit and therefore the condition of the rendered
attribute defaults to false
and hence the button is never rendered and thus also never invoked.
Your bean needs to be placed in the view scope.
@ManagedBean
@ViewScoped
public class ManageSquareBean
This way the bean (and all boolean conditions it holds) will live as long as you're interacting with the same view.
Upvotes: 2
Reputation: 186
I'm sure that the panelGroup isn't the problem.
I have 2 suggestions for you:
1) Check if you have inherited forms. Sometimes it happens that a form element resides in another form through the templating approach. JSF can't handle this correctly
2) Perhaps you need to wrap the f:metadata with a define tag and the name metadata.
http://javaserverfaces.java.net/nonav/docs/2.0/pdldocs/facelets/f/metadata.html
<ui:define name="metadata">
<f:metadata>
<f:viewParam name="squareName" value="#{manageSquareBean.squareName}"/>
<f:event type="preRenderView" listener="#{manageSquareBean.initialize}"/>
</f:metadata>
</ui:define>
Upvotes: 0