I think the best way to resolve this problem is just to paste my code :
Selector bean
@ManagedBean(name="selector")
@RequestScoped
public class Selector {
@ManagedProperty(value="#{param.page}")
private String page;
private String profilePage;
@PostConstruct
public void init() {
if(profilePage==null || profilePage.trim().isEmpty()) {
this.profilePage="main";
}
if(page==null || page.trim().isEmpty()) {
this.page="homepage";
}
}
public String getProfilePage() { System.out.println("GET ="+profilePage); return profilePage; }
public void setProfilePage(String profilePage) { this.profilePage=profilePage; }
public String getPage() { return page; }
public void setPage(String page) { this.page=page; }
}
profile.xhtml
<h:panelGroup layout="block" id="profileContent">
<h:panelGroup rendered="#{selector.profilePage=='main'}">
<ui:include src="/profile/profile_main.xhtml" />
</h:panelGroup>
<h:panelGroup rendered="#{selector.profilePage=='edit'}">
<ui:include src="/profile/profile_edit.xhtml" />
</h:panelGroup>
</h:panelGroup>
profile_main.xhtml
<h:form id="formProfileMain" prependId="false">
<h:panelGroup layout="block">
<h:outputScript name="jsf.js" library="javax.faces" target="head" />
<h:outputLabel value="MAIN" />
<h:panelGroup layout="block" >
<h:commandButton value="Edit Button">
<f:setPropertyActionListener target="#{selector.profilePage}" value="edit" />
<f:ajax event="action" render=":profileContent"/>
</h:commandButton>
</h:panelGroup>
</h:panelGroup>
</h:form>
profile_edit.xhtml
<h:panelGroup layout="block" id="profileEditContent">
<h:panelGroup rendered="#{selector.profilePage=='edit'}">
<h:form id="formProfileEdit" prependId="false">
<h:panelGroup layout="block">
<h:outputScript name="jsf.js" library="javax.faces" target="head" />
<h:outputLabel value="EDIT" />
<h:panelGroup layout="block">
<h:commandButton value="Confirm Edit">
<f:setPropertyActionListener target="#{selector.profilePage}" value="editConfirm" />
<f:ajax event="action" render=":profileEditContent"/>
</h:commandButton>
<h:commandButton value="Back">
<f:setPropertyActionListener target="#{selector.profilePage}" value="main" />
<f:ajax event="action" render=":profileEdit"/>
</h:commandButton>
</h:panelGroup>
</h:panelGroup>
</h:form>
</h:panelGroup>
<h:panelGroup rendered="#{selector.profilePage=='editConfirm'}">
<h:outputLabel value="FINALLY IM HERE" />
</h:panelGroup>
</h:panelGroup>
If i click first on Edit Button and than on Confirm Edit, i attempt to get (as result) the page with the label FINALLY IM HERE Unfortunatly this doesnt happen. I click on Edit Button and after, if i click on Confirm Edit, nothing happen.
What am I wrong? Cheers
UPDATE WITH NEW VERSION
bean
@ManagedBean
@ViewScoped
public class ProfileSelector {
private String profilePage;
@PostConstruct
public void init() {
if(profilePage==null || profilePage.trim().isEmpty()) {
this.profilePage="main";
}
}
public String getProfilePage() { return profilePage; }
public void setProfilePage(String profilePage) { this.profilePage=profilePage; }
}
profile.xhtml
<h:panelGroup layout="block" id="profileContent">
<h:form id="formProfile" prependId="false">
<h:outputScript name="jsf.js" library="javax.faces" target="head" />
<h:panelGroup rendered="#{profileSelector.profilePage=='main'}">
<ui:include src="/profile/profile_main.xhtml" />
</h:panelGroup>
<h:panelGroup rendered="#{profileSelector.profilePage=='edit'}">
<ui:include src="/profile/profile_edit.xhtml" />
</h:panelGroup>
</h:form>
</h:panelGroup>
profile_main.xhtml
<h:panelGroup layout="block">
<h:outputLabel value="MAIN" />
<h:panelGroup layout="block">
<h:commandButton value="Edit Button">
<f:setPropertyActionListener target="#{profileSelector.profilePage}" value="edit" />
<f:ajax event="action" render=":profileContent"/>
</h:commandButton>
</h:panelGroup>
</h:panelGroup>
profile_edit.xhtml
<h:panelGroup layout="block" id="profileContentEdit">
<h:panelGroup rendered="#{profileSelector.profilePage=='edit'}">
<h:panelGroup layout="block">
<h:outputLabel value="EDIT" />
<h:panelGroup layout="block" styleClass="profilo_3">
<h:commandButton value="Confirm Edit">
<f:setPropertyActionListener target="#{profileSelector.profilePage}" value="editConfirm" />
<f:ajax event="action" render=":profileContentEdit"/>
</h:commandButton>
<h:commandButton value="Back">
<f:setPropertyActionListener target="#{profileSelector.profilePage}" value="main" />
<f:ajax event="action" render=":profileContent"/>
</h:commandButton>
</h:panelGroup>
</h:panelGroup>
</h:panelGroup>
<h:panelGroup rendered="#{profileSelector.profilePage=='editConfirm'}">
<h:outputLabel value="FINALLY Im HERE" />
</h:panelGroup>
</h:panelGroup>
Well, that gets complicated. Whether the
UICommand
action will be invoked also depends on the result of therendered
attribute of the component or one of its parents. Because the bean is in the request scope theprofilePage
defaults back tomain
in the next request, so therendered
attribute of the edit section evaluatesfalse
, so the buttons in the edit section will not invoke any actions. This has been answered in your previous question.In theory, marking the bean
@ViewScoped
should fix this because it retains the bean state in subsequent views. However, in your particular case there are two problems which prevents it from working properly.First, you're using a
@ManagedProperty
which refers to a value which is in a shorter scope (the#{param}
is basically request scoped). You would need to split theprofilePage
into another bean and mark this@ViewScoped
.Second, due to a currently still open bug in JSF2 (issue 1718), your particular case would still not work because you have multiple
<h:form>
in a differentrendered
condition which are all attached to the same bean. This specific situation would lead tojavax.faces.ViewState
being completely missing in the returned response. This will cause the view scoped bean to be garbaged and recreated (and theprofilePage
defaults tomain
again). As a temporary workaround, you need to extract and merge the forms into one form inprofile.xhtml
, as direct child of the first<h:panelGroup>
.Update: If your sole concern is that you want to connect the beans to each other, then you could split the beans as follows:
The view scoped bean is then accessible in the request scoped bean this way.
Or, if you really want to have a single bean, you can as a workaround also replace
@ManagedProperty
as follows: