You basically have 2 options of constructing a wizard-type flow. The first option is to show all steps within one view, the other one is to have the number of views as there are steps in your wizard.
All wizard steps within one view
As Xtreme Biker rightfully mentions the most natural way of designing the view is separating every step in a conditionally rendered component, like <h:panelGroup>
and updating bean's property currentStep upon entering a different wizard step.
The basic view setup:
<h:panelGroup id="step1">
<h:panelGroup rendered="#{bean.currentStep eq 1}">
<ui:include src="step1.xhtml"/>
</h:panelGroup>
</h:panelGroup>
...
The included page (step2.xhtml):
...
<h:commandButton value="Back" action="#{bean.back}">
<f:ajax execute="step2" render="step1 step2"/>
</h:commandButton>
<h:commandButton value="Forward" action="#{bean.forward}">
<f:ajax execute="step2" render="step1 step2"/>
</h:commandButton>
...
Backing bean:
@ManagedBean
@ViewScoped
public class Bean implements Serializable {
...
private int currentStep = 1;//getter+setter
public String forward() {
...
if(currentStep == 2) {
doSomethingWithValues();
currentStep++;
}
...
}
public String back() {
...
if(currentStep == 2) {
clearNecessaryValues();
currentStep--;
}
...
}
}
This approach is good if you want to embed a customized content in your view. If you are good with a 'standard' approach, you would rather not reinvent the wheel and use <p:wizard>
tag of Primefaces library, which does basically the same under the covers.
Every wizard step in a different view
If you are going to navigate to a different view by calling back/forward buttons and returning different navigation case outcomes each time your job can be done by using a flash
object to transfer needed data to the next view.
So, the setup is going to be: wizard/step2.xhtml
(one view per step) and one view scoped bean Bean
.
One of the views (the second view)
...
<h:commandButton value="Back" action="#{bean.back}">
</h:commandButton>
<h:commandButton value="Forward" action="#{bean.forward}">
</h:commandButton>
...
Backing bean:
@ManagedBean
@ViewScoped
public class Bean implements Serializable {
...
private int currentStep = 1;//getter+setter
@ManagedProperty("#{flash}")
private Flash flash;//getter+setter
private Data step1Data;
private Data step2Data;
private Data step3Data;
...
@PostConstruct
public void init() {
int step = Integer.parseInt(flash.get("newStep"));
Data step1 = (Data)flash.get("step1");
Data step2 = (Data)flash.get("step2");
Data step3 = (Data)flash.get("step3");
this.currentStep = step;
this.step1Data = step1;
this.step2Data = step2;
this.step3Data = step3;
...
}
public String forward() {
...
if(currentStep == 2) {
doSomethingWithValues();
currentStep++;
flash.put("step", currentStep);
flash.put("step1", step1Data);
flash.put("step2", step2Data);
return "wizard/step3?faces-redirect=true"
}
...
}
public String back() {
...
if(currentStep == 2) {
clearNecessaryValues();
currentStep--;
flash.put("step", currentStep);
flash.put("step1", step1Data);
return "wizard/step1?faces-redirect=true"
}
...
}
}