Master Details Tutorial

compared with
Current by Matthew Cowell
on Oct 29, 2012 19:20.

These lines were removed. This word was removed.
These lines were added. This word was added.

View page history

There are 32 changes. View first change.

 h1. Master Details
  h1. Master Details Tutorial
Master-Details update forms are commonly used for selecting an item from a list and then updating the details of that item. This example will show how you can easily set up a form to select an employee and update the employee details.
h1. {anchor:EasyAjaxPush-EasyAjaxPushTutorial}Master Details Tutorial
Master-Details update forms are commonly used for selecting an item from a list and then updating the details of that item. This example will show how you can easily set up a form to select an employee and update the employee details.
 This tutorial uses an ICE dataTable with a rowSelector.
  This tutorial uses an ace:dataTable with a rowSelector.
 Here is the entire list of steps worked through during this tutorial:
# [Make the masterDetails Project|]
 # [Add ICEfaces|]
 # [Create masterDetails.xhtml|]
 # [Create|]
 # [Create|]
 # [Deploy the Application|]
  # [Make the masterDetails Project|#step1]
 # [Add ICEfaces|#step2]
 # [Create masterDetails.xhtml|#step3]
 # [Create|#step4]
 # [Create|#step5]
 # [Deploy the Application|#step6]
* [Tutorial Source Code Downloads|]
  * Tutorial Source Code Downloads (coming soon)
h3. {anchor:EasyAjaxPush-DevelopmentToolsUsed}Development Tools Used
  h3. Development Tools Used
 The following tools were used to create the project.
* [Eclipse|] IDE for Java EE Developers - Version Juno
  * [Eclipse|] IDE for Java EE Developers - Version Juno
 * [Tomcat 7.x|] Web Server
 * [Java 6.x|]
 * ICEfaces 3
h3. {anchor:EasyAjaxPush-1.Makethe%7B%7BeasyAjaxPush}{anchor:EasyAjaxPush-step1}1. Make the masterDetails Project
  h3. {anchor:step1}1. Make the masterDetails Project
 * Using Eclipse create a new Dynamic Web Project called masterDetails.
 ** Target runtime: Apache Tomcat v7.0
 ** Dynamic web module version: 3.0
 ** Configuration: JavaServer Faces v2.0 Project (Mojarra)
h3. {anchor:EasyAjaxPush-2.AddICEfacesandICEpush}{anchor:EasyAjaxPush-step2}2. Add ICEfaces
  h3. {anchor:step2}2. Add ICEfaces
 Add the icefaces.jar (from the ICEfaces 3 bundle) to your project, either through a custom User Library or by putting them into masterDetails /WEB-INF/lib/. The approach doesn't matter as long as the jars are included in the deployed war file.
h3. {anchor:EasyAjaxPush-3.Create%7B%7Bcolor.xhtml%7}{anchor:EasyAjaxPush-step3}3. Create masterDetails.xhtml
  h3. {anchor:step3}3. Create masterDetails.xhtml
 Create a new page called masterDetails.xhtml and paste the code below:
 We will build this page in three stages to see the different elements. First we will put the master table at the top.
 <?xml version='1.0' encoding='UTF-8' ?>
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "">
 <html xmlns=""
  <title>Master/Details demo</title>
<link rel="stylesheet" type="text/css"
  href="./xmlhttp/css/rime/rime.css" />
   <ice:outputStyle href="./xmlhttp/css/rime/rime.css"/>
  <h:body styleClass="ice-skin-rime">
  <h:form id="master">
  <ace:panel header="Staff List" toggleable="true" style="width: 50%">
<ice:dataTable id="masterTable" value="#{dataTableBean.personData}"
  <ice:column id="id" headerText="ID">
  <ice:rowSelector value="#{person.selected}"
  selectionListener="#{dataTableBean.selectionListener}" />
  <h:outputText id="idCell" value="#{}" />
  <ice:column id="name" headerText="Full Name">
  <h:outputText id="nameCell" value="#{}" />
  <ice:column id="address" headerText="Address">
  <h:outputText id="addressCell" value="#{person.address}" />
  <ace:dataTable id="masterTable" value="#{dataTableBean.personData}"
  selectionMode="single" var="person"
  <ace:column id="id" headerText="ID">#{}</ace:column>
  <ace:column id="name" headerText="Full Name"> #{} </ace:column>
  <ace:column id="address" headerText="Address">#{person.address}</ace:column>
<p />
 We used an ACE dataTable component to output a list of staff. We have specified a row listener so that we can take a staff member in the master list and updated their details below.
  <h:form id="details">
  <ace:panel header="Staff Member Details" toggleable="true"
  style="width: 50%" collapsed="#{dataTableBean.detailsHidden}">
  <ice:panelGrid columns="2">
  <ice:outputLabel for="firstName" value="First Name" />
  <h:inputText id="firstName"
  value="#{dataTableBean.personDetails.firstName}" size="55">
<f:ajax event="change" listener="#{dataTableBean.changeListener}"/>
   <ace:ajax event="change" listener="#{dataTableBean.changeListener}" />
  <ice:outputLabel for="lastName" value="Last Name" />
  <h:inputText id="lastName"
  value="#{dataTableBean.personDetails.lastName}" size="55">
<f:ajax event="change" listener="#{dataTableBean.changeListener}"/>
   <ace:ajax event="change" listener="#{dataTableBean.changeListener}" />
  <ice:outputLabel for="address" value="Address" />
  <h:inputText id="address"
  value="#{dataTableBean.personDetails.address}" size="55">
<f:ajax event="change" listener="#{dataTableBean.changeListener}" />
  <ace:ajax event="change" listener="#{dataTableBean.changeListener}" />
<ice:outputText />
   <f:facet name="footer">
  <ice:commandButton value="Update Details"
  action="#{}" />
 Here we can see the details form. We use a panelGrid for formatting and an ajax event to detect changes in the form to make sure the user does not switch records when they have unsaved data.
 Finally, we have a popup dialog box to warn the user if they attempt to change users with unsaved data
  <h:form id="confirmDialog">
  <!-- Confirm Dialog -->
  <ice:panelPopup visible="#{dataTableBean.confirmDialog}" modal="true">
  <f:facet name="header">
<ice:panelGroup styleClass="headerStyleClass">
   <ice:panelGroup style="background-color: #DC143C;">
  <ice:outputText value="Warning" />
  <f:facet name="body">
<ice:panelGroup styleClass="bodyStyleClass">
   <ice:panelGroup style="background-color: #FFFFFF;">
value="You have unsaved data. &lt;br/&gt; Are you sure you want to change to a new master record?"
   value="You have unsaved data. Are you sure you want to change to a new record?"
  escape="false" />
  <h:commandButton value="Yes" action="#{dataTableBean.confirmYes}" />
  <h:commandButton value="No" action="#{dataTableBean.confirmNo}" />
h3. {anchor:step4}4. Create
 Create a new Java class file called Person in the package org.icefaces.tutorial.masterdetails.model and paste the code below:
This class is ViewScoped so one bean instance will be created for each client session. The current HTTP session ID for this client will be tracked. An instance of the MessageBean is injected so that text can be added as needed.
 Currently no Ajax Push is used in the above code, since we will add that further below.
  package org.icefaces.tutorial.masterdetails.model;
 import javax.faces.bean.ManagedBean;
 import javax.faces.bean.RequestScoped;
h3. {anchor:EasyAjaxPush-6.Create%7B%7BTextModel.jav}{anchor:EasyAjaxPush-step6}{anchor:EasyAjaxPush-7.DeploytheApplication}{anchor:EasyAjaxPush-step7}6. Deploy the Application
 public class Person implements Serializable, Cloneable{
  private static final long serialVersionUID = -3540661397516075104L;
  public Person(Integer id, String firstName, String lastName, String address) {
  this.firstName = firstName;
  this.lastName = lastName;
  this.address = address;
  private Integer id;
  private String firstName;
  private String lastName;
  private String address;
  private Boolean selected;
 Once the application is built and deployed and running it will look fairly basic. Clicking a color button will refresh the list of messages, since no Ajax Push has been added yet. Ideally we want to be able to open multiple web browsers and see each others color choices immediately through Ajax Push.
   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 String getAddress() {
  return address;
  public void setAddress(String address) {
  this.address = address;
  public String getName(){
  return firstName + " " + lastName;
  public Integer getId() {
  return id;
  public void setId(Integer id) { = id;
  public Boolean getSelected() {
  return selected;
  public void setSelected(Boolean selected) {
  this.selected = selected;
  * Method to create a copy of this object.
  * The super method does a copy of each member of this object into a new object
  public Object clone() throws CloneNotSupportedException {
  return super.clone();
  public boolean equals(Object obj) {
  if (obj instanceof Person) {
  Person compare = (Person) obj;
  if (compare.getId() == this.getId()) {
  return true;
  return false;
  return super.equals(obj);
 This class is a model of a Person (in our case, an employee). It contains fields for id, first name, last name, address. In the future it could be extended for different kinds of people (full time, part time, contractor, ect) as required.
 h3. {anchor:step5}5. Create
 We will now create the DataTableBean. The contents of this bean are fairy simple.&nbsp; On initialization, it creates a few new People objects so that we can use them in a table.&nbsp; The changeListener is called when a change occurs in the details table.&nbsp; The selectionListener is called when a user selects an employee from the master table.
 Create a new Java class file called DataTableBean in the package org.icefaces.tutorial.masterdetails.beans and paste the code below:
 package org.icefaces.tutorial.masterdetails.beans;
 import java.util.ArrayList;
 import java.util.List;
 import javax.annotation.PostConstruct;
 import javax.faces.bean.ManagedBean;
 import javax.faces.bean.ViewScoped;
 import javax.faces.event.AjaxBehaviorEvent;
 import org.icefaces.tutorial.masterdetails.model.Person;
 import com.icesoft.faces.component.ext.RowSelectorEvent;
 public class DataTableBean implements Serializable {
  private static final long serialVersionUID = -2904483316550697214L;
  private List<Person> personData;
  private Person personDetails;
  private Person newIndex;
  private boolean confirmDialog = false;
  private boolean detailsHidden = true;
  private boolean change = false;
  public void initData() {
  personData = new ArrayList<Person>(3);
  // Add some people
  personData.add(new Person(1, "Peter", "Parker",
  "150 Main Street, New York, NY, USA"));
  personData.add(new Person(2, "Ryan", "Penner",
  "528 Newmarket Road, Wilston, QLD, Australia"));
  personData.add(new Person(3, "Paul", "Wilson",
  "50 Big Ben Road, London, UK"));
  public List<Person> getPersonData() {
  return personData;
  public void setPersonData(List<Person> personData) {
  this.personData = personData;
  public Person getPersonDetails() {
  return personDetails;
  public void setPersonDetails(Person personDetails) {
  this.personDetails = personDetails;
  public void selectionListener(SelectEvent event) {
  // First selection or no changes to the current record
  Person temp = (Person) event.getObject();
  if (personDetails == null || !change) {
  try {
  setPersonDetails((Person) temp.clone());
  } catch (CloneNotSupportedException e) {
  detailsHidden = false;
  // Something else is already selected
  else if (!getPersonDetails().equals(event.getObject())) {
  // Throw a warning to the user
  newIndex = (Person) temp.clone();
  } catch (CloneNotSupportedException e) {
  public void confirmYes() {
  confirmDialog = false;
  detailsHidden = false;
  change = false; // We discard the old record
  public void confirmNo() {
  newIndex = null;
  confirmDialog = false;
  public void changeListener(AjaxBehaviorEvent event) {
  change = true;
  public void save() {
  // Reset the change flag
  change = false;
  // Save the person
  int index = personData.indexOf(getPersonDetails());
  personData.set(index, personDetails);
  public boolean isConfirmDialog() {
  return confirmDialog;
  public void setConfirmDialog(boolean confirmDialog) {
  this.confirmDialog = confirmDialog;
  public boolean isDetailsHidden() {
  return detailsHidden;
  public void setDetailsHidden(boolean detailsHidden) {
  this.detailsHidden = detailsHidden;
 h3. {anchor:step6}6. Deploy the application
 Once the application is built and deployed you will be able to select a employee from the table at the top of the page and edit their details on the table below. Your deployed application should look like this:

© Copyright 2018 ICEsoft Technologies Canada Corp.