I'm developing a web application with JSF 2.1 and Primefaces 5.1 in the front-end. I have a page that allows me to manage players (players.xhtml
). In that page I include another one (search_players.xhtml
) that defines the search functionality (it has the input fields and the dataTable showing the players):
players.xhtml
<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:p="http://primefaces.org/ui"
xmlns:f="http://java.sun.com/jsf/core"
template="resources/templates/template.xhtml">
<ui:define name="contextual_content">
<ui:include src="resources/snippets/search_players.xhtml"/>
<p:commandButton id="add_player_button_id" value="#{msgs.add}" onclick="PF('dlg').show();" />
...
</ui:define>
</ui:composition>
search_players.xhtml
<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:p="http://primefaces.org/ui"
xmlns:f="http://java.sun.com/jsf/core">
<h:form id="search_player_form_id">
<p:panelGrid columns="3">
<h:panelGroup layout="block" >
#{msgs.id}: <p:inputText value="#{playersBean.id}" styleClass="search_input_text" />
</h:panelGroup>
...
</p:panelGrid>
<p:dataTable id="players_table_id" var="player" value="#{playersBean.players}" rowKey="#{player.id}" paginator="true"
paginatorTemplate="{CurrentPageReport} {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}"
rowsPerPageTemplate="5,10,15" selectionMode="single" selection="#{playersBean.player}">
...
</p:dataTable>
</h:form>
</ui:composition>
As a backing bean, I have a ViewScoped
managed bean that has the list of players to populate the table, the placeholders for the input fields and the selected player (from the table).
- PlayersBean.java
@ManagedBean
@ViewScoped
public class PlayersBean implements Serializable {
private static final long serialVersionUID = 1L;
private static final Logger logger = LogManager.getLogger(PlayersBean.class);
/* List to populate table */
private List<DtoPlayer> players;
/* Placeholders */
private BigDecimal id;
...
/* Selected player*/
private DtoPlayer player;
@EJB
private PlayersService playersService;
@EJB
private StartupBean startupBean;
public PlayersBean() {
logger.entry();
}
@PostConstruct
public void init() {
...
}
public void searchPlayers() {
...
}
public void createPlayer() {
...
}
// getters and setters
}
Everything works fine here.
Now I want to have a page (similar to players.xhtml
) that allows the management of configurations (configurations.xhtml
). Creating a configuration involves a set of steps, for which I have created a wizard. In two of those steps, users have to choose a player (the source and the destination) - that's why I have the snippet for searching players defined in a separated .xhtml, to be able to reuse it now.
- configurations.xhtml
<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:p="http://primefaces.org/ui"
xmlns:f="http://java.sun.com/jsf/core"
template="resources/templates/template.xhtml">
<ui:define name="contextual_content">
<p:commandButton id="add_configuration_button_id" value="#{msgs.add}" onclick="PF('dlg').show();" />
<p:dialog header="#{msgs.add_configuration}" widgetVar="dlg" closeOnEscape="true" width="1050" height="600" minWidth="1050" minHeight="600">
<h:form id="create_configuration_form_id">
<p:wizard id="create_configuration_wizard" styleClass="wizard" widgetVar="wiz" flowListener="#{configurationsBean.handleFlow}">
<p:tab ...>
...
</p:tab>
<p:tab id="create_configuration_wizard_player_source_tab" title="#{msgs.source}">
<f:subview id="player_source">
<ui:include src="resources/snippets/search_players.xhtml"/>
</f:subview>
</p:tab>
<p:tab id="create_configuration_wizard_player_destination_tab" title="#{msgs.destination}">
<f:subview id="player_destination">
<ui:include src="resources/snippets/search_players.xhtml"/>
</f:subview>
</p:tab>
...
<p:tab id="create_configuration_wizard_confirm" title="#{msgs.confirm}">
<p:panel header="#{msgs.confirm}">
...
<p:commandButton id="save_configuration_button_id" value="#{msgs.save}" action="#{configurationsBean.createConfiguration}" onclick="PF('dlg').hide();" update=":search_configuration_form_id:configurations_table_id" />
</p:panel>
</p:tab>
</p:wizard>
</h:form>
</p:dialog>
</ui:define>
</ui:composition>
And for this page, I follow the same approach as with players: I have a ViewScoped
managed bean. This one injects references to 2 instances of PlayersBean
(the source and destination).
- ConfigurationsBean.java
@ManagedBean
@ViewScoped
public class ConfigurationsBean implements Serializable {
private static final long serialVersionUID = 1L;
private static final Logger logger = LogManager.getLogger(ConfigurationsBean.class);
/* List to populate table */
private List<DtoConfiguration> configurations;
/* Placeholders */
private BigDecimal id;
...
@ManagedProperty(value="#{playersBean}")
private PlayersBean playersSourceBean;
@ManagedProperty(value="#{playersBean}")
private PlayersBean playersDestinationBean;
@EJB
private ConfigurationsService configurationsService;
@EJB
private StartupBean startupBean;
public ConfigurationsBean() {
logger.entry();
}
@PostConstruct
public void init() {
...
}
public void searchConfigurations() {
...
}
public void createConfiguration() {
try {
logger.entry();
logger.info(this.playersSourceBean == this.playersDestinationBean ? "same player" : "different players");
...
}
public String handleFlow(FlowEvent event) {
String currentStepId = event.getNewStep();
logger.info("CurrentStepId: " + currentStepId);
return event.getNewStep();
}
// getters and setters
}
And now the problem arises. The wizard gets created correctly but both source and destination player steps use the same PlayersBean
instance. So I select the source player in the "Source Player" step, and when I step to the "Destination Player", the player in the table is already selected. In the end, when I submit, I can see that the source and destination players are the same. But I want to have 2 different instances! How can I solve this problem?
PS: In case you need to know any project configuration (like web.xml, faces-config.xml) let me know.