I recently needed to create a "JSF Editable Datatable" where all fields (or a subset) could be edited at once. Here's what I came up with...
My requirements:
- Use a standard JSF datatable.
- When user clicks the Edit Button, all fields (or a subset) become editable inputText components.
- When a user clicks the Save Button, the changes will be saved to the affected objects and persisted to the DB.
My implementation involves the following:
- IceFaces, Hibernate, Spring.
- 1 jspx page with an ice:datatable component.
- 1 backing bean with edit and save actions for the datatable.
The jspx:
<jsp:root
xmlns:jsp="http://java.sun.com/JSP/Page"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:c="http://java.sun.com/jstl/core"
xmlns:ice="http://www.icesoft.com/icefaces/component"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
version="2.0">
<jsp:directive.page contentType="text/html"/>
<jsp:output omit-xml-declaration="no"
doctype-root-element="html"
doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN"
doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"/>
<ice:dataTable id="editableDatatable" value="#{backingBean.elements}" var="element">
<ice:column>
<f:facet name="header">
<ice:outputText value="Value 1"/>
</f:facet>
<h:inputText disabled="#{backingbean.elementsDisabled}"
value="#{element.value1}"/>
</ice:column>
<ice:column>
<f:facet name="header">
<ice:outputText value="Value 2"/>
</f:facet>
<h:inputText disabled="#{backingbean.elementsDisabled}"
value="#{element.value2}"/>
</ice:column>
</ice:dataTable>
<br/>
<!--Buttons will be hidden or visible based on whether the table is in edit mode or display mode-->
<div id="editElement" style="display:block;">
<!--Put the table in edit mode by enabling the inputtext components-->
<ice:commandButton value="Edit Element" partialSubmit="true"
onclick="toggleLayerOn('updateElement');toggleLayerOff('editElement');">
<f:setPropertyActionListener value="#{false}" target="#{backingBean.elementsDisabled}"/>
</ice:commandButton>
</div>
<div id="updateElement" style="display:none;">
<!--Save the changes and return to display mode-->
<ice:commandButton action="#{backingBean.updateElementValues}" value="Update Element Values"
partialSubmit="true"
onclick="toggleLayerOn('editElement');toggleLayerOff('updateElement');"/>
<!--Cancel the changes and return to display mode-->
<ice:commandButton value="Cancel Changes" partialSubmit="true"
onclick="toggleLayerOn('editElement');toggleLayerOff('updateElement');">
<f:setPropertyActionListener value="#{true}" target="#{backingBean.elementsDisabled}"/>
</ice:commandButton>
</div>
</jsp:root>
The backing bean. Please note the upateElementValues() method. This gets the editableDataTable from the FacesContext, casts it to an HtmlDataTable, loops over the rows of this datatable, and casts each row to an Element. These Elements contain the updated values entered by the user. You must then load the original Elements via Id and make the necessary changes before persisting the updates back to the database. Make sure to set your datatable rowIndex back to -1 (see code) or there will be JSF errors.
import com.icesoft.faces.component.ext.HtmlDataTable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.faces.component.UIComponent;
import javax.faces.component.UIData;
import javax.faces.context.FacesContext;
import java.util.*;
public class BackingBean {
public static final Logger log = LoggerFactory.getLogger(BackingBean.class);
private ElementDao elementDao;
private boolean elementsDisabled = true;
private List<Element> elements = new ArrayList<Element>();
public BackingBean() {
>//get all the elements from the database
elements = elementDao.getAllElements();
}
public void setElementDao(ElementDao elementDao) {
this.elementDao = elementDao;
}
public void updateElementValues() {
>//get the datatable as a UI component
UIComponent comp = FacesContext.getCurrentInstance().getViewRoot().findComponent("editableDataTable");
if (comp != null) {
UIData uIData = (UIData) comp;
HtmlDataTable myTable = (HtmlDataTable) uIData;
for (int i = 0; i < myTable.getRowCount(); i++) {
>//loop over the rows
myTable.setRowIndex(i);
>//get the values that the user edited for this row
Element modifiedElement = (Element) myTable.getRowData();
>//print the values to verify they are correct
log.info("Value 1 " + modifiedElement.getValue1());
log.info("Value 2 " + modifiedElement.getValue2());
>//load the element from the database
Element originalElement = elementDao.load(modifiedElement.getId());
originalElement.setValue1(modifiedElement.getValue1());
originalElement.setValue2(modifiedElement.getValue2());
>//update the values in the database for the given element
elementDao.update(originalElement);
}
>//make sure to set the row Index back to -1!!!
myTable.setRowIndex(-1);
}
>//disable the inputtext components, they should only be enabled during "edit mode"
setElementsDisabled(true);
}
public boolean isElementsDisabled() {
return elementsDisabled;
}
public void setElementsDisabled(boolean elementsDisabled) {
this.elementsDisabled = elementsDisabled;
}
public List<Element> getElements() {
return elements;
}
public void setElements(List<Element> elements) {
this.elements = elements;
}
}
The object:
import javax.persistence.Id;
import javax.persistence.GeneratedValue;
import javax.persistence.Column;
public class Element {
@Id
@GeneratedValue(generator = "hibernate-uuid")
private String id;
@Column(nullable = false)
private String value1;
@Column(nullable = false)
private String value2;
public Element(String value1, String value2) {
this.value1 = value1;
this.value2 = value2;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getValue1() {
return value1;
}
public void setValue1(String value1) {
this.value1 = value1;
}
public String getValue2() {
return value2;
}
public void setValue2(String value2) {
this.value2 = value2;
}
}
4 Comments
Leave a comment
0 TrackBacks
Listed below are links to blogs that reference this entry: JSF Editable Datatable.
TrackBack URL for this entry: http://www.nearinfinity.com/mt/mt-tb.cgi/469



Hello...
I am working on JSF RAD.
I had used relational Record List whic uses DataTable to Get The list of all the Records in My DB.In That i need to have a radio button.Its like Examination where questions and options are displayed in data table and user has to select one option through a radio button. My radio Buttons are generated Dynamically depending on Number of Rows. But when i get the value traversing the Component tree and printing the values it returns null... please help me out if possible... its urgent since i am working on a project.
Thanks in Advance
Hi All,
Is this code is right or not?cuz i have same requirement and when i click on save button i got empty datatable.i meann rowsize is 0.plz help me...
kinjal,
The code does work. I'm not sure why you're seeing an empty datatable. Perhaps your backing bean is not scoped correctly?
Hi, I'm just curious why You don't save changed data from list elements(changes are updated there during update model phase), and why You are using partialSubmit in commandButton? I'm still learning jsf, so just not sure what is right....