Wizard creates a workflow by creating multiple steps out of a single page form. Only current step is processed partially and next step is displayed if current step passes validations. Wizard flow is sequential by default and this can be managed using the optional ajax flowListeners, simply outcome of a flowListener defines the next step to display.
<style>
.label {
width: 20%;
padding: 4px;
}
.value {
width: 80%;
padding: 4px;
}
.grid {
width: 100%;
}
.error {
color: red;
}
.outputLabel {
font-weight: bold;
}
.grid {
width: 33%;
padding: 4px;
}
</style>
<div class="card">
<h:form>
<p:growl id="growl" sticky="true" showDetail="true"/>
<p:wizard flowListener="#{userWizard.onFlowProcess}">
<p:tab id="personal" title="Personal">
<p:panel header="Personal Details">
<p:messages/>
<h:panelGrid columns="2" columnClasses="label, value">
<h:outputText value="Firstname: *"/>
<p:inputText value="#{userWizard.user.firstname}" required="true" label="Firstname"/>
<h:outputText value="Lastname: *"/>
<p:inputText value="#{userWizard.user.lastname}" required="true" label="Lastname"/>
<h:outputText value="Age: "/>
<p:inputText value="#{userWizard.user.age}"/>
<h:outputText value="Skip to last: "/>
<h:selectBooleanCheckbox value="#{userWizard.skip}"/>
</h:panelGrid>
</p:panel>
</p:tab>
<p:tab id="address" title="Address">
<p:panel header="Address Details">
<p:messages/>
<h:panelGrid columns="2" columnClasses="label, value">
<h:outputText value="Street: "/>
<p:inputText value="#{userWizard.user.street}"/>
<h:outputText value="Postal Code: "/>
<p:inputText value="#{userWizard.user.postalCode}"/>
<h:outputText value="City: "/>
<p:inputText value="#{userWizard.user.city}"/>
<h:outputText value="Skip to last: "/>
<h:selectBooleanCheckbox value="#{userWizard.skip}"/>
</h:panelGrid>
</p:panel>
</p:tab>
<p:tab id="contact" title="Contact">
<p:panel header="Contact Information">
<p:messages/>
<h:panelGrid columns="2" columnClasses="label, value">
<h:outputText value="Email: *"/>
<p:inputText value="#{userWizard.user.email}" required="true" label="Email"/>
<h:outputText value="Phone: "/>
<p:inputText value="#{userWizard.user.phone}"/>
<h:outputText value="Additional Info: "/>
<p:inputText value="#{userWizard.user.info}"/>
</h:panelGrid>
</p:panel>
</p:tab>
<p:tab id="confirm" title="Confirmation">
<p:panel header="Confirmation">
<h:panelGrid id="confirmation" columns="3" columnClasses="grid,grid,grid">
<h:panelGrid columns="2" columnClasses="label, value">
<h:outputText value="Firstname: "/>
<h:outputText value="#{userWizard.user.firstname}" styleClass="outputLabel"/>
<h:outputText value="Lastname: "/>
<h:outputText value="#{userWizard.user.lastname}" styleClass="outputLabel"/>
<h:outputText value="Age: "/>
<h:outputText value="#{userWizard.user.age}" styleClass="outputLabel"/>
</h:panelGrid>
<h:panelGrid columns="2" columnClasses="label, value">
<h:outputText value="Street: "/>
<h:outputText value="#{userWizard.user.street}" styleClass="outputLabel"/>
<h:outputText value="Postal: "/>
<h:outputText value="#{userWizard.user.postalCode}" styleClass="outputLabel"/>
<h:outputText value="City: "/>
<h:outputText value="#{userWizard.user.city}" styleClass="outputLabel"/>
</h:panelGrid>
<h:panelGrid columns="2" columnClasses="label, value">
<h:outputText value="Email: "/>
<h:outputText value="#{userWizard.user.email}" styleClass="outputLabel"/>
<h:outputText value="Phone "/>
<h:outputText value="#{userWizard.user.phone}" styleClass="outputLabel"/>
<h:outputText value="Info: "/>
<h:outputText value="#{userWizard.user.info}" styleClass="outputLabel"/>
<h:outputText/>
<h:outputText/>
</h:panelGrid>
</h:panelGrid>
<p:commandButton value="Submit" action="#{userWizard.save}" update="growl" process="@this"/>
</p:panel>
</p:tab>
</p:wizard>
</h:form>
</div>
@Named
@ViewScoped
public class UserWizard implements Serializable {
private User user = new User();
private boolean skip;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public void save() {
FacesMessage msg = new FacesMessage("Successful", "Welcome :" + user.getFirstname());
FacesContext.getCurrentInstance().addMessage(null, msg);
}
public boolean isSkip() {
return skip;
}
public void setSkip(boolean skip) {
this.skip = skip;
}
public String onFlowProcess(FlowEvent event) {
if (skip) {
skip = false; //reset in case user goes back
return "confirm";
}
else {
return event.getNewStep();
}
}
}
public class User implements Serializable {
private String firstname;
private String lastname;
private Integer age;
private String street;
private String city;
private String postalCode;
private String info;
private String email;
private String phone;
public String getFirstname() {
return firstname;
}
public void setFirstname(String firstname) {
this.firstname = firstname;
}
public String getLastname() {
return lastname;
}
public void setLastname(String lastname) {
this.lastname = lastname;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getStreet() {
return street;
}
public void setStreet(String street) {
this.street = street;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getPostalCode() {
return postalCode;
}
public void setPostalCode(String postalCode) {
this.postalCode = postalCode;
}
public String getInfo() {
return info;
}
public void setInfo(String info) {
this.info = info;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
}