MasterDetail groups contents into levels (sections) and saves page space. Smart and flexible navigation between levels via built-in breadcrumbs or command components gives users a neat and stylish interface.
Straightforward navigation by means of the pe:selectDetailLevel handler. Context values (any objects) are passed from level to level and available via context variables. The level to go to is set via level or step (default step=1); the breadcrumb text via levelLabel or the label facet.
Wizard-like navigation with form fields. The header and footer facets render content above and below the levels, shared between all levels, which allows a custom title bar instead of the built-in breadcrumbs.
Complex master-detail views with CRUD operations and a server-side flow listener. The SelectLevelEvent passed into the listener and its return value control the level to navigate to: after a successful save of the detail view (level 2) go back to the master view (level 1), otherwise stay.
Each level in the flow is represented by a pe:masterDetailLevel component. Switching between levels is done
by the pe:selectDetailLevel handler and is based on AJAX, so each level is loaded dynamically.
pe:selectDetailLevel can be attached to any ajaxified PrimeFaces or non-PrimeFaces component, typically
CommandLink, CommandButton, MenuItem, RemoteCommand, HotKey and any component with an attached f:ajax / p:ajax.
This gives flexible control over partial validation and over calling action / actionListener during
navigation. The area updated during navigation is set automatically to the pe:masterDetail component; processed
and updated areas can be controlled more precisely by process / update. Partial validation can be
skipped by process="@none" or immediate="true", and is always skipped for navigation via breadcrumbs.
Other features are a server-side listener invoked when a navigation attempt takes place and the header / footer facets.
Attention: reference the pe:masterDetail in the update attribute of command components
manually if the page has auto-updating components such as p:growl or p:message with p:autoUpdate.
Known limitation: MasterDetail does not work inside data iteration components extending UIData,
e.g. inside a DataTable: navigation will not work there.
<style>
.levelTitle {
padding: 4px 6px 4px 6px;
margin-right: 3px;
border-radius: 4px;
}
.levelTitle.p-state-hover {
background: var(--p-primary-color);
color: var(--p-primary-contrast-color);
}
table .formColumn1 {
padding-right: 10px;
text-align: right;
white-space: nowrap;
width: 1%;
}
table .formColumn2 input {
width: 200px;
}
[id$="personDetail"] .p-datalist {
width: 200px;
}
</style>
<div class="card">
<h5>Basic navigation level by level</h5>
<p>Straightforward navigation by means of the <code>pe:selectDetailLevel</code> handler. Context values (any objects) are passed from level to level and available via context variables. The level to go to is set via <code>level</code> or <code>step</code> (default <code>step=1</code>); the breadcrumb text via <code>levelLabel</code> or the <code>label</code> facet.</p>
<h:form id="formBasicNavigation">
<pe:masterDetail id="masterDetail" level="#{simpleMasterDetailController.currentLevel}">
<pe:masterDetailLevel level="1" levelLabel="Sports">
<p:dataTable id="sports" value="#{simpleMasterDetailController.sports}" var="sport">
<p:column headerText="Sport">
<p:commandLink value="#{sport.name}">
<pe:selectDetailLevel contextValue="#{sport}"/>
</p:commandLink>
</p:column>
<p:column headerText="Number of countries with leagues">
<h:outputText value="#{sport.countriesWithLeague.size()}"/>
</p:column>
</p:dataTable>
</pe:masterDetailLevel>
<pe:masterDetailLevel level="2" contextVar="sport" levelLabel="Countries having #{sport.name} leagues">
<p:dataTable id="countries" value="#{sport.countriesWithLeague}" var="country">
<p:column headerText="Country">
<p:commandLink value="#{country.name}">
<pe:selectDetailLevel contextValue="#{country}"/>
</p:commandLink>
</p:column>
<p:column headerText="Code">
<h:outputText value="#{country.code}"/>
</p:column>
</p:dataTable>
</pe:masterDetailLevel>
<pe:masterDetailLevel level="3" contextVar="country" levelLabel="#{country.sport} leagues of #{country.name}">
<p:dataTable id="leauges" value="#{country.leagues}" var="league">
<p:column headerText="League">
<h:outputText value="#{league.name}"/>
</p:column>
<p:column headerText="Number of teams">
<h:outputText value="#{league.numberOfTeam}"/>
</p:column>
</p:dataTable>
<h:panelGrid columns="2" style="margin-top: 10px">
<p:commandButton value="Go to Sports" icon="pi pi-fast-backward">
<pe:selectDetailLevel level="1"/>
</p:commandButton>
<p:commandButton value="Go to Countries" icon="pi pi-step-backward">
<pe:selectDetailLevel step="-1"/>
</p:commandButton>
</h:panelGrid>
</pe:masterDetailLevel>
</pe:masterDetail>
</h:form>
</div>
<div class="card">
<h5>Wizard-like navigation with forms</h5>
<p>Wizard-like navigation with form fields. The <code>header</code> and <code>footer</code> facets render content above and below the levels, shared between all levels, which allows a custom title bar instead of the built-in breadcrumbs.</p>
<h:form id="formWizardLikeNavigation">
<pe:masterDetail id="masterDetail" level="#{wizardMasterDetailController.currentLevel}" showBreadcrumb="false">
<f:facet name="header">
<p:messages showDetail="true"/>
<h:panelGroup layout="block" style="margin-top: 10px;">
<h:panelGroup styleClass="levelTitle p-state-default
#{wizardMasterDetailController.currentLevel eq 1 ? 'p-state-hover' : ''}">
<h:outputText value="Personal"/>
</h:panelGroup>
<h:panelGroup styleClass="levelTitle p-state-default
#{wizardMasterDetailController.currentLevel eq 2 ? 'p-state-hover' : ''}">
<h:outputText value="Address"/>
</h:panelGroup>
<h:panelGroup styleClass="levelTitle p-state-default
#{wizardMasterDetailController.currentLevel eq 3 ? 'p-state-hover' : ''}">
<h:outputText value="Contact"/>
</h:panelGroup>
<h:panelGroup styleClass="levelTitle p-state-default
#{wizardMasterDetailController.currentLevel eq 4 ? 'p-state-hover' : ''}">
<h:outputText value="Confirmation"/>
</h:panelGroup>
</h:panelGroup>
</f:facet>
<pe:masterDetailLevel level="1">
<p:panel header="Personal Details">
<h:panelGrid columns="2" columnClasses="formColumn1,formColumn2">
<h:outputText value="Firstname: *"/>
<p:inputText required="true" label="Firstname"
value="#{wizardMasterDetailController.user.firstname}"/>
<h:outputText value="Lastname: *"/>
<p:inputText required="true" label="Lastname"
value="#{wizardMasterDetailController.user.lastname}"/>
<h:outputText value="Age: "/>
<p:inputText value="#{wizardMasterDetailController.user.age}"/>
</h:panelGrid>
</p:panel>
<p:commandButton value="Next" process="masterDetail"
style="margin-top: 10px;" icon="pi pi-arrow-right">
<pe:selectDetailLevel step="1"/>
</p:commandButton>
<p:commandButton value="Go to Save" process="masterDetail"
style="margin-top: 10px;" icon="pi pi-step-forward">
<pe:selectDetailLevel level="4"/>
</p:commandButton>
</pe:masterDetailLevel>
<pe:masterDetailLevel level="2">
<p:panel header="Adress Details">
<h:panelGrid columns="2" columnClasses="formColumn1,formColumn2">
<h:outputText value="Street: "/>
<p:inputText value="#{wizardMasterDetailController.user.street}"/>
<h:outputText value="Postal Code: "/>
<p:inputText value="#{wizardMasterDetailController.user.postalCode}"/>
<h:outputText value="City: "/>
<p:inputText value="#{wizardMasterDetailController.user.city}"/>
</h:panelGrid>
</p:panel>
<p:commandButton value="Back" style="margin-top: 10px;" icon="pi pi-arrow-left"
process="@this" immediate="true">
<pe:selectDetailLevel step="-1"/>
</p:commandButton>
<p:commandButton value="Next" process="masterDetail"
style="margin-top: 10px;" icon="pi pi-arrow-right">
<pe:selectDetailLevel step="1"/>
</p:commandButton>
</pe:masterDetailLevel>
<pe:masterDetailLevel level="3">
<p:panel header="Contact Information">
<h:panelGrid columns="2" columnClasses="formColumn1,formColumn2">
<h:outputText value="Email: *"/>
<p:inputText required="true" label="Email"
value="#{wizardMasterDetailController.user.email}"/>
<h:outputText value="Phone: "/>
<p:inputText value="#{wizardMasterDetailController.user.phone}"/>
<h:outputText value="Additional Info: "/>
<p:inputText value="#{wizardMasterDetailController.user.info}"/>
</h:panelGrid>
</p:panel>
<p:commandButton value="Back" style="margin-top: 10px;" icon="pi pi-arrow-left"
process="@this" immediate="true">
<pe:selectDetailLevel step="-1"/>
</p:commandButton>
<p:commandButton value="Next" process="masterDetail"
style="margin-top: 10px;" icon="pi pi-arrow-right">
<pe:selectDetailLevel step="1"/>
</p:commandButton>
</pe:masterDetailLevel>
<pe:masterDetailLevel level="4">
<p:panel header="Confirmation">
<h:panelGrid id="confirmation" columns="2" columnClasses="formColumn1,formColumn2">
<h:outputText value="Firstname: "/>
<h:outputText value="#{wizardMasterDetailController.user.firstname}"/>
<h:outputText value="Lastname: "/>
<h:outputText value="#{wizardMasterDetailController.user.lastname}"/>
<h:outputText value="Age: "/>
<h:outputText value="#{wizardMasterDetailController.user.age}"/>
<h:outputText value="Street: "/>
<h:outputText value="#{wizardMasterDetailController.user.street}"/>
<h:outputText value="Postal Code: "/>
<h:outputText value="#{wizardMasterDetailController.user.postalCode}"/>
<h:outputText value="City: "/>
<h:outputText value="#{wizardMasterDetailController.user.city}"/>
<h:outputText value="Email: "/>
<h:outputText value="#{wizardMasterDetailController.user.email}"/>
<h:outputText value="Phone "/>
<h:outputText value="#{wizardMasterDetailController.user.phone}"/>
<h:outputText value="Info: "/>
<h:outputText value="#{wizardMasterDetailController.user.info}"/>
</h:panelGrid>
</p:panel>
<p:commandButton value="Back" style="margin-top: 10px;" icon="pi pi-arrow-left"
process="@this" immediate="true">
<pe:selectDetailLevel step="-1"/>
</p:commandButton>
<p:commandButton value="Submit" process="masterDetail"
actionListener="#{wizardMasterDetailController.save}"
style="margin-top: 10px;" icon="pi pi-save">
<pe:selectDetailLevel level="1"/>
</p:commandButton>
</pe:masterDetailLevel>
</pe:masterDetail>
</h:form>
</div>
<div class="card">
<h5>Master-detail views with CRUD operations</h5>
<p>Complex master-detail views with CRUD operations and a server-side flow listener. The <code>SelectLevelEvent</code> passed into the listener and its return value control the level to navigate to: after a successful save of the detail view (level 2) go back to the master view (level 1), otherwise stay.</p>
<h:form id="formComplexNavigation">
<pe:masterDetail id="masterDetail" selectLevelListener="#{selectLevelListener.handleNavigation}"
showAllBreadcrumbItems="true">
<f:facet name="header">
<p:messages showDetail="false" showSummary="true"/>
</f:facet>
<pe:masterDetailLevel level="1">
<f:facet name="label">
<h:outputFormat value="Overview {0}">
<f:param value="Persons"/>
</h:outputFormat>
</f:facet>
<p:dataTable id="persons" value="#{complexMasterDetailController.persons}" var="pers">
<p:column headerText="Name">
<p:commandLink value="#{pers.name}">
<pe:selectDetailLevel contextValue="#{pers}"/>
</p:commandLink>
</p:column>
<p:column headerText="Tax Class">
<h:outputText value="#{pers.taxClass}"/>
</p:column>
<p:column headerText="Birth Date">
<h:outputText value="#{pers.birthDate}">
<f:convertDateTime pattern="dd.MM.yyyy"/>
</h:outputText>
</p:column>
</p:dataTable>
</pe:masterDetailLevel>
<pe:masterDetailLevel level="2" contextVar="person" levelLabel="Person Detail">
<h:panelGrid id="personDetail" columns="2" columnClasses="formColumn1,formColumn2">
<h:outputText value="Name (string)"/>
<p:inputText value="#{person.name}" required="true" label="Name"/>
<h:outputText value="Tax Class (number)"/>
<p:inputText value="#{person.taxClass}" required="true" label="Tax Class">
<f:validateLength maximum="1"/>
</p:inputText>
<h:outputText value="Birth Date (date dd.MM.yyyy)"/>
<p:inputText value="#{person.birthDate}" required="true" label="Birth Date">
<f:convertDateTime pattern="dd.MM.yyyy"/>
</p:inputText>
<h:outputText value="Language skills"/>
<h:panelGrid columns="2" style="vertical-align: middle;">
<p:dataList value="#{person.languageSkills}" var="skill" itemType="circle">
<h:outputText value="#{skill}"/>
</p:dataList>
<p:commandLink immediate="true" style="padding:5px 0 0 8px; vertical-align:middle;">
<h:graphicImage library="images" name="flashlight_plus.png" style="border:none;"/>
<pe:selectDetailLevel contextValue="#{person}" preserveInputs="@all"/>
<pe:tooltip value="Add language skills"/>
</p:commandLink>
</h:panelGrid>
</h:panelGrid>
<p:commandButton value="Save with success" process="masterDetail"
action="#{complexMasterDetailController.saveSuccess(person)}"
style="margin-top:10px;" icon="pi pi-save">
<pe:selectDetailLevel level="1"/>
</p:commandButton>
<p:commandButton value="Save with failure" process="masterDetail"
action="#{complexMasterDetailController.saveFailure(person)}"
style="margin-top:10px;" icon="pi pi-save">
<pe:selectDetailLevel level="1"/>
</p:commandButton>
<p:commandButton type="button" value="Delete" onclick="PF('deletedDlg').show()" style="margin-top:10px;"/>
<p:dialog header="Delete confirmation" widgetVar="deletedDlg" resizable="false">
<h:panelGroup layout="block" style="padding:5px;">
<h:outputText value="Are you sure you want to delete this person?"/>
</h:panelGroup>
<p:commandButton id="deleteBtn" value="Delete"
action="#{complexMasterDetailController.delete(person)}" process="@this"
style="margin-top:10px;">
<pe:selectDetailLevel level="1"/>
</p:commandButton>
<p:commandButton value="Cancel" type="button" onclick="PF('deletedDlg').hide();"
style="margin-top:10px;"/>
</p:dialog>
</pe:masterDetailLevel>
<pe:masterDetailLevel level="3" contextVar="person" levelLabel="Language skills">
<h:panelGrid columns="2" columnClasses="formColumn1,formColumn2">
<h:outputText value="Choose language skill"/>
<p:selectOneMenu id="languageSkills" value="#{complexMasterDetailController.languageSkillToAdd}"
style="width:200px;">
<f:selectItems value="#{complexMasterDetailController.availableLanguageSkills}"/>
<p:ajax event="valueChange" process="masterDetail"
listener="#{complexMasterDetailController.addLanguageSkill(person)}"/>
<pe:selectDetailLevel step="-1"/>
</p:selectOneMenu>
</h:panelGrid>
</pe:masterDetailLevel>
</pe:masterDetail>
</h:form>
</div>
package org.primefaces.extensions.showcase.controller.masterdetail;
import java.io.Serial;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import jakarta.faces.view.ViewScoped;
import jakarta.inject.Named;
import org.primefaces.extensions.showcase.model.masterdetail.Country;
import org.primefaces.extensions.showcase.model.masterdetail.League;
import org.primefaces.extensions.showcase.model.masterdetail.Sport;
/**
* SimpleMasterDetailController.
*
* @author Oleg Varaksin / last modified by $Author$
* @version $Revision$
*/
@Named
@ViewScoped
public class SimpleMasterDetailController implements Serializable {
@Serial
private static final long serialVersionUID = 20111120L;
private List<Sport> sports;
private int currentLevel = 1;
public SimpleMasterDetailController() {
if (sports == null) {
sports = new ArrayList<Sport>();
// football
List<Country> countries = new ArrayList<Country>();
Country country = new Country("Switzerland", "CH", "Football", getLeagues("Switzerland"));
countries.add(country);
country = new Country("England", "UK", "Football", getLeagues("England"));
countries.add(country);
country = new Country("Spain", "ES", "Football", getLeagues("Spain"));
countries.add(country);
country = new Country("Netherlands", "NL", "Football", getLeagues("Netherlands"));
countries.add(country);
sports.add(new Sport("Football", countries));
// basketball
countries = new ArrayList<Country>();
country = new Country("Germany", "DE", "Basketball", getLeagues("Germany"));
countries.add(country);
country = new Country("USA", "US", "Basketball", getLeagues("USA"));
countries.add(country);
country = new Country("Poland", "PL", "Basketball", getLeagues("Poland"));
countries.add(country);
sports.add(new Sport("Basketball", countries));
// ice hockey
countries = new ArrayList<Country>();
country = new Country("Russia", "RU", "Ice Hockey", getLeagues("Russia"));
countries.add(country);
country = new Country("Canada", "CA", "Ice Hockey", getLeagues("Canada"));
countries.add(country);
sports.add(new Sport("Ice Hockey", countries));
}
}
public List<Sport> getSports() {
return sports;
}
public int getCurrentLevel() {
return currentLevel;
}
public void setCurrentLevel(final int currentLevel) {
this.currentLevel = currentLevel;
}
private List<League> getLeagues(final String country) {
final List<League> leagues = new ArrayList<League>();
leagues.add(new League(country + " SuperLeague", 20));
leagues.add(new League(country + " NotBadLeague", 15));
leagues.add(new League(country + " CrapLeague", 30));
return leagues;
}
}
package org.primefaces.extensions.showcase.model.masterdetail;
import java.io.Serial;
import java.io.Serializable;
import java.util.List;
/**
* Sport model class.
*
* @author Oleg Varaksin / last modified by $Author$
* @version $Revision$
*/
public class Sport implements Serializable {
@Serial
private static final long serialVersionUID = 20111120L;
private String name;
private List<Country> countriesWithLeague;
public Sport(String name, List<Country> countriesWithLeague) {
this.name = name;
this.countriesWithLeague = countriesWithLeague;
}
public String getName() {
return name;
}
public List<Country> getCountriesWithLeague() {
return countriesWithLeague;
}
}
package org.primefaces.extensions.showcase.model.masterdetail;
import java.io.Serial;
import java.io.Serializable;
import java.util.List;
/**
* Country model class.
*
* @author Oleg Varaksin / last modified by $Author$
* @version $Revision$
*/
public class Country implements Serializable {
@Serial
private static final long serialVersionUID = 20111120L;
private String name;
private String code;
private String sport;
private List<League> leagues;
public Country(String name, String code, String sport, List<League> leagues) {
this.name = name;
this.code = code;
this.sport = sport;
this.leagues = leagues;
}
public String getName() {
return name;
}
public String getCode() {
return code;
}
public String getSport() {
return sport;
}
public List<League> getLeagues() {
return leagues;
}
}
package org.primefaces.extensions.showcase.model.masterdetail;
import java.io.Serial;
import java.io.Serializable;
/**
* League model class.
*
* @author Oleg Varaksin / last modified by $Author$
* @version $Revision$
*/
public class League implements Serializable {
@Serial
private static final long serialVersionUID = 20111120L;
private String name;
private int numberOfTeam;
public League(String name, int numberOfTeam) {
this.name = name;
this.numberOfTeam = numberOfTeam;
}
public String getName() {
return name;
}
public int getNumberOfTeam() {
return numberOfTeam;
}
}
package org.primefaces.extensions.showcase.controller.masterdetail;
import java.io.Serial;
import java.io.Serializable;
import jakarta.faces.application.FacesMessage;
import jakarta.faces.context.FacesContext;
import jakarta.faces.event.ActionEvent;
import jakarta.faces.view.ViewScoped;
import jakarta.inject.Named;
import org.primefaces.extensions.showcase.model.masterdetail.User;
/**
* WizardMasterDetailController.
*
* @author Oleg Varaksin / last modified by $Author$
* @version $Revision$
*/
@Named
@ViewScoped
public class WizardMasterDetailController implements Serializable {
@Serial
private static final long serialVersionUID = 20120209L;
private User user = new User();
private int currentLevel = 1;
public User getUser() {
return user;
}
public void setUser(final User user) {
this.user = user;
}
public int getCurrentLevel() {
return currentLevel;
}
public void setCurrentLevel(final int currentLevel) {
this.currentLevel = currentLevel;
}
public void save(final ActionEvent actionEvent) {
final FacesMessage msg = new FacesMessage("Saved successful", "Welcome :" + user.getFirstname());
FacesContext.getCurrentInstance().addMessage(null, msg);
// create new empty user
user = new User();
currentLevel = 1;
}
}
package org.primefaces.extensions.showcase.model.masterdetail;
import java.io.Serial;
import java.io.Serializable;
/**
* User class.
*
* @author ova / last modified by $Author$
* @version $Revision$
*/
public class User implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
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;
}
}
package org.primefaces.extensions.showcase.controller.masterdetail;
import jakarta.enterprise.context.RequestScoped;
import jakarta.inject.Named;
import org.primefaces.extensions.component.masterdetail.SelectLevelEvent;
/**
* SelectLevelListener
*
* @author ova / last modified by $Author$
* @version $Revision$
*/
@Named
@RequestScoped
public class SelectLevelListener {
private boolean errorOccured = false;
public int handleNavigation(final SelectLevelEvent selectLevelEvent) {
if (errorOccured) {
return 2;
}
else {
return selectLevelEvent.getNewLevel();
}
}
public void setErrorOccured(final boolean errorOccured) {
this.errorOccured = errorOccured;
}
}
package org.primefaces.extensions.showcase.controller.masterdetail;
import java.io.Serial;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import jakarta.el.ELContext;
import jakarta.faces.FacesException;
import jakarta.faces.application.FacesMessage;
import jakarta.faces.context.FacesContext;
import jakarta.faces.model.SelectItem;
import jakarta.faces.view.ViewScoped;
import jakarta.inject.Named;
import org.primefaces.extensions.showcase.model.Person;
/**
* ComplexMasterDetailController.
*
* @author Oleg Varaksin / last modified by $Author$
* @version $Revision$
*/
@Named
@ViewScoped
public class ComplexMasterDetailController implements Serializable {
@Serial
private static final long serialVersionUID = 20111120L;
private List<Person> persons;
private List<SelectItem> availableLanguageSkills = null;
private final List<String> selectedLanguageSkills = new ArrayList<String>();
private String languageSkillToAdd;
public ComplexMasterDetailController() {
if (persons == null) {
persons = new ArrayList<Person>();
final Calendar calendar = Calendar.getInstance();
calendar.set(1972, 5, 25);
persons.add(new Person("1", "Max Mustermann", 1, calendar.getTime()));
calendar.set(1981, 12, 10);
persons.add(new Person("2", "Sara Schmidt", 2, calendar.getTime()));
calendar.set(1968, 2, 13);
persons.add(new Person("3", "Jasper Morgan", 3, calendar.getTime()));
}
}
public List<Person> getPersons() {
return persons;
}
public List<SelectItem> getAvailableLanguageSkills() {
if (availableLanguageSkills == null) {
availableLanguageSkills = new ArrayList<SelectItem>();
availableLanguageSkills.add(new SelectItem("English", "English"));
availableLanguageSkills.add(new SelectItem("German", "German"));
availableLanguageSkills.add(new SelectItem("Russian", "Russian"));
availableLanguageSkills.add(new SelectItem("Turkish", "Turkish"));
availableLanguageSkills.add(new SelectItem("Dutch", "Dutch"));
availableLanguageSkills.add(new SelectItem("French", "French"));
availableLanguageSkills.add(new SelectItem("Italian", "Italian"));
}
return availableLanguageSkills;
}
public List<String> getSelectedLanguageSkills() {
return selectedLanguageSkills;
}
public void setLanguageSkillToAdd(final String languageSkillToAdd) {
this.languageSkillToAdd = languageSkillToAdd;
}
public String getLanguageSkillToAdd() {
return languageSkillToAdd;
}
public String saveSuccess(final Person person) {
final FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_INFO,
"Person " + person.getName() + " has been saved", null);
FacesContext.getCurrentInstance().addMessage(null, message);
return null;
}
public String saveFailure(final Person person) {
final FacesContext fc = FacesContext.getCurrentInstance();
final ELContext elContext = fc.getELContext();
SelectLevelListener selectLevelListener;
try {
selectLevelListener = (SelectLevelListener) elContext.getELResolver().getValue(elContext, null,
"selectLevelListener");
selectLevelListener.setErrorOccured(true);
}
catch (final RuntimeException e) {
throw new FacesException(e.getMessage(), e);
}
final FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR,
"Person " + person.getName() + " could not be saved", null);
FacesContext.getCurrentInstance().addMessage(null, message);
return null;
}
public String delete(final Person person) {
for (final Person pers : persons) {
if (pers.getId().equals(person.getId())) {
persons.remove(pers);
break;
}
}
return null;
}
public void addLanguageSkill(final Person person) {
if (languageSkillToAdd != null) {
person.addLanguageSkill(languageSkillToAdd);
}
languageSkillToAdd = null;
}
}
package org.primefaces.extensions.showcase.model;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
/**
* Person model class.
*
* @author Oleg Varaksin / last modified by $Author$
* @version $Revision$
*/
public class Person implements Serializable {
@Serial
private static final long serialVersionUID = 20111128L;
private String id;
private String name;
private int taxClass;
private Date birthDate;
private Set<String> languageSkills = new HashSet<String>();
public Person(String id, String name, int taxClass, Date birthDate) {
this.id = id;
this.name = name;
this.taxClass = taxClass;
this.birthDate = birthDate;
}
public String getId() {
return id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getTaxClass() {
return taxClass;
}
public void setTaxClass(int taxClass) {
this.taxClass = taxClass;
}
public Date getBirthDate() {
return birthDate;
}
public void setBirthDate(Date birthDate) {
this.birthDate = birthDate;
}
public String[] getLanguageSkills() {
return languageSkills.toArray(new String[languageSkills.size()]);
}
public void addLanguageSkill(String languageSkill) {
languageSkills.add(languageSkill);
}
}