Working with Data Components

Exclusive offer: get 50% off this eBook here
PrimeFaces Beginner's Guide

PrimeFaces Beginner's Guide — Save 50%

Get your JSF-based projects up and running with this easy-to-implement guide on PrimeFaces with this book and ebook

$29.99    $15.00
by K. Siva Prasad Reddy | November 2013 | JBoss Open Source

In this article by K. Siva Prasad Reddy, author of PrimeFaces Beginner's Guide, we will learn about several data iteration components of PrimeFaces, which include DataList, DataTable, DataGrid, and so on. These can be used to display data in a tabular format. Also, PrimeFaces provides the DataExporter component to export data into PDF, Excel, CSV, or XML formats.

The topics covered in this article are:

  • Displaying data in a list layout using DataList
  • Displaying data in a tabular format using DataTable
  • Displaying data in a grid layout using the DataGrid component
  • Exporting data into PDF, XLS, CSV, and XML formats using DataExporter

(For more resources related to this topic, see here.)

Introducing the DataList component

The DataList component displays a collection of data in the list layout with several display types and supports AJAX pagination. The DataList component iterates through a collection of data and renders its child components for each item.

Let us see how to use <p:dataList>to display a list of tag names as an unordered list:

<p:dataList value="#{tagController.tags}" var="tag" type="unordered" itemType="disc"> #{tag.label} </p:dataList>

The preceding <p:dataList> component displays tag names as an unordered list of elements marked with disc type bullets. The valid type options are unordered, ordered, definition, and none.

We can use type="unordered" to display items as an unordered collection along with various itemType options such as disc, circle, and square. By default, type is set to unordered and itemType is set to disc.

We can set type="ordered" to display items as an ordered list with various itemType options such as decimal, A, a, and i representing numbers, uppercase letters, lowercase letters, and roman numbers respectively.

Time for action – displaying unordered and ordered data using DataList

Let us see how to display tag names as unordered and ordered lists with various itemType options.

  1. Create <p:dataList> components to display items as unordered and ordered lists using the following code:

    <h:form> <p:panel header="Unordered DataList"> <h:panelGrid columns="3"> <h:outputText value="Disc"/> <h:outputText value="Circle" /> <h:outputText value="Square" /> <p:dataList value="#{tagController.tags}" var="tag" itemType="disc"> #{tag.label} </p:dataList> <p:dataList value="#{tagController.tags}" var="tag" itemType="circle"> #{tag.label} </p:dataList> <p:dataList value="#{tagController.tags}" var="tag" itemType="square"> #{tag.label} </p:dataList> </h:panelGrid> </p:panel> <p:panel header="Ordered DataList"> <h:panelGrid columns="4"> <h:outputText value="Number"/> <h:outputText value="Uppercase Letter" /> <h:outputText value="Lowercase Letter" /> <h:outputText value="Roman Letter" /> <p:dataList value="#{tagController.tags}" var="tag" type="ordered"> #{tag.label} </p:dataList> <p:dataList value="#{tagController.tags}" var="tag" type="ordered" itemType="A"> #{tag.label} </p:dataList> <p:dataList value="#{tagController.tags}" var="tag" type="ordered" itemType="a"> #{tag.label} </p:dataList> <p:dataList value="#{tagController.tags}" var="tag" type="ordered" itemType="i"> #{tag.label} </p:dataList> </h:panelGrid> </p:panel> </h:form>

  2. Implement the TagController.getTags() method to return a collection of tag objects:

    public class TagController { private List<Tag> tags = null; public TagController() { tags = loadTagsFromDB(); } public List<Tag> getTags() { return tags; } }

What just happened?

We have created DataList components to display tag names as an unordered list using type="unordered" and as an ordered list using type="ordered" with various supported itemTypes values. This is shown in the following screenshot:

Using DataList with pagination support

DataList has built-in pagination support that can be enabled by setting paginator="true". By enabling pagination, the various page navigation options will be displayed using the default paginator template. We can customize the paginator template to display only the desired options.

The paginator can be customized using the paginatorTemplate option that accepts the following keys of UI controls:

  • FirstPageLink
  • LastPageLink
  • PreviousPageLink
  • NextPageLink
  • PageLinks
  • CurrentPageReport
  • RowsPerPageDropdown

Note that {RowsPerPageDropdown} has its own template, and options to display is provided via the rowsPerPageTemplate attribute (for example, rowsPerPageTemplate="5,10,15"). Also, {CurrentPageReport} has its own template defined with the currentPageReportTemplate option. You can use the {currentPage}, {totalPages}, {totalRecords}, {startRecord}, and {endRecord} keywords within the currentPageReport template. The default is "{currentPage} of {totalPages}".

The default paginator template is "{FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink}".

We can customize the paginator template to display only the desired options.

For example: {CurrentPageReport} {FirstPageLink} {PreviousPageLink} {PageLinks}
{NextPageLink} {LastPageLink} {RowsPerPageDropdown}

The paginator can be positioned using the paginatorPosition attribute in three different locations: top, bottom, or both(default).

The DataList component provides the following attributes for customization:

  • rows: This is the number of rows to be displayed per page.
  • first: This specifies the index of the first row to be displayed. The default is 0.
  • paginator: This enables pagination. The default is false.
  • paginatorTemplate: This is the template of the paginator.
  • rowsPerPageTemplate: This is the template of the rowsPerPage dropdown.
  • currentPageReportTemplate: This is the template of the currentPageReport UI.
  • pageLinks: This specifies the maximum number of page links to display. The default value is 10.
  • paginatorAlwaysVisible: This defines if paginator should be hidden when the total data count is less than the number of rows per page. The default is true.
  • rowIndexVar: This specifies the name of the iterator to refer to for each row index.
  • varStatus: This specifies the name of the exported request scoped variable to represent the state of the iteration same as in <ui:repeat> attribute varStatus.

Time for action – using DataList with pagination

Let us see how we can use the DataList component's pagination support to display five tags per page.

Create a DataList component with pagination support along with custom paginatorTemplate:

<p:panel header="DataList Pagination"> <p:dataList value="#{tagController.tags}" var="tag" id="tags"
type="none" paginator="true" rows="5" paginatorTemplate="{CurrentPageReport} {FirstPageLink}
{PreviousPageLink} {PageLinks} {NextPageLink}
{LastPageLink} {RowsPerPageDropdown}" rowsPerPageTemplate="5,10,15"> <f:facet name="header"> Tags </f:facet> <h:outputText value="#{tag.id} -
#{tag.label}" style="margin-left:10px" /> <br/> </p:dataList> </p:panel>

What just happened?

We have created a DataList component along with pagination support by setting paginator="true". We have customized the paginator template to display additional information such as CurrentPageReport and RowsPerPageDropdown. Also, we have used the rowsPerPageTemplate attribute to specify the values for RowsPerPageDropdown. The following screenshot displays the result:

Displaying tabular data using the DataTable component

DataTable is an enhanced version of the standard DataTable that provides various additional features such as:

  • Pagination
  • Lazy loading
  • Sorting
  • Filtering
  • Row selection
  • Inline row/cell editing
  • Conditional styling
  • Expandable rows
  • Grouping and SubTable and many more

In our TechBuzz application, the administrator can view a list of users and enable/disable user accounts. First, let us see how we can display list of users using basic DataTable as follows:

<p:dataTable id="usersTbl" var="user" value="#{adminController.users}"> <f:facet name="header"> List of Users </f:facet> <p:column headerText="Id"> <h:outputText value="#{user.id}" /> </p:column> <p:column headerText="Email"> <h:outputText value="#{user.emailId}" /> </p:column> <p:column headerText="FirstName"> <h:outputText value="#{user.firstName}" /> </p:column> <p:column headerText="Disabled"> <h:outputText value="#{user.disabled}" /> </p:column> <f:facet name="footer"> Total no. of Users: #{fn:length(adminController.users)}. </f:facet> </p:dataTable>

  • The following screenshot shows us the result:

PrimeFaces 4.0 introduced the Sticky component and provides out-of-the-box support for DataTable to make the header as sticky while scrolling using the stickyHeader attribute:

<p:dataTable var="user" value="#{adminController.users}"
stickyHeader="true">
... </p:dataTable>

Using pagination support

If there are a large number of users, we may want to display users in a page-by-page style. DataTable has in-built support for pagination.

Time for action – using DataTable with pagination

Let us see how we can display five users per page using pagination.

Create a DataTable component using pagination to display five records per page, using the following code:

<p:dataTable id="usersTbl" var="user" value="#{adminController.users}" paginator="true" rows="5" paginatorTemplate="{CurrentPageReport} {FirstPageLink}
{PreviousPageLink} {PageLinks}
{NextPageLink} {LastPageLink} {RowsPerPageDropdown}"
currentPageReportTemplate="( {startRecord} - {endRecord}) of
{totalRecords} Records." rowsPerPageTemplate="5,10,15"> <p:column headerText="Id"> <h:outputText value="#{user.id}" /> </p:column> <p:column headerText="Email"> <h:outputText value="#{user.emailId}" /> </p:column> <p:column headerText="FirstName"> <h:outputText value="#{user.firstName}" /> </p:column> <p:column headerText="Disabled"> <h:outputText value="#{user.disabled}" /> </p:column> </p:dataTable>

What just happened?

We have created a DataTable component with the pagination feature to display five rows per page. Also, we have customized the paginator template and provided an option to change the page size dynamically using the rowsPerPageTemplate attribute.

Using columns sorting support

DataTable comes with built-in support for sorting on a single column or multiple columns. You can define a column as sortable using the sortBy attribute as follows:

<p:column headerText="FirstName" sortBy="#{user.firstName}"> <h:outputText value="#{user.firstName}" /> </p:column>

You can specify the default sort column and sort order using the sortBy and sortOrder attributes on the <p:dataTable> element:

<p:dataTable id="usersTbl2" var="user" value="#{adminController.users}"
sortBy="#{user.firstName}" sortOrder="descending"> </p:dataTable>

The <p:dataTable> component's default sorting algorithm uses a Java comparator, you can use your own customized sort method as well:

<p:column headerText="FirstName" sortBy="#{user.firstName}" sortFunction=
"#{adminController.sortByFirstName}
"> <h:outputText value="#{user.firstName}" /> </p:column> public int sortByFirstName(Object firstName1, Object firstName2) { //return -1, 0 , 1 if firstName1 is less than, equal to
or greater than firstName2 respectively return ((String)firstName1).compareToIgnoreCase(((String)firstName2)); }

By default, DataTable's sortMode is set to single, to enable sorting on multiple columns set sortMode to multiple. In multicolumns' sort mode, you can click on a column while the metakey (Ctrl or command) adds the column to the order group:

<p:dataTable id="usersTbl" var="user"
value="#{adminController.users}" sortMode="multiple"> </p:dataTable>

Using column filtering support

DataTable provides support for column-level filtering as well as global filtering (on all columns) and provides an option to hold the list of filtered records. In addition to the default match mode startsWith, we can use various other match modes such as endsWith, exact, and contains.

Time for action – using DataTable with filtering

Let us see how we can use filters with users' DataTable.

  1. Create a DataTable component and apply column-level filters and a global filter to apply filter on all columns:

    <p:dataTable widgetVar="userTable" var="user" value=
    "#{adminController.users}" filteredValue="#{adminController.filteredUsers}" emptyMessage="No Users found for the given Filters"> <f:facet name="header"> <p:outputPanel> <h:outputText value="Search all Columns:" /> <p:inputText id="globalFilter"
    onkeyup="userTable.filter()" style="width:150px" /> </p:outputPanel> </f:facet> <p:column headerText="Id"> <h:outputText value="#{user.id}" /> </p:column> <p:column headerText="Email" filterBy="#{user.emailId}" footerText="contains" filterMatchMode="contains"> <h:outputText value="#{user.emailId}" /> </p:column> <p:column headerText="FirstName" filterBy="#{user.firstName}"
    footerText="startsWith"> <h:outputText value="#{user.firstName}" /> </p:column> <p:column headerText="LastName" filterBy="#{user.lastName}" filterMatchMode="endsWith" footerText="endsWith"> <h:outputText value="#{user.lastName}" /> </p:column> <p:column headerText="Disabled" filterBy="#{user.disabled}" filterOptions="#{adminController.userStatusOptions}" filterMatchMode="exact" footerText="exact"> <h:outputText value="#{user.disabled}" /> </p:column> </p:dataTable>

  2. Initialize userStatusOptions in AdminController ManagedBean.

    @ManagedBean @ViewScoped public class AdminController { private List<User> users = null; private List<User> filteredUsers = null; private SelectItem[] userStatusOptions; public AdminController() { users = loadAllUsersFromDB(); this.userStatusOptions = new SelectItem[3]; this.userStatusOptions[0] = new SelectItem("", "Select"); this.userStatusOptions[1] = new SelectItem("true", "True"); this.userStatusOptions[2] = new SelectItem("false", "False"); } //setters and getters }

What just happened?

We have used various filterMatchMode instances, such as startsWith, endsWith, and contains, while applying column-level filters. We have used the filterOptions attribute to specify the predefined filter values, which is displayed as a select drop-down list. As we have specified filteredValue="#{adminController.filteredUsers}", once the filters are applied the filtered users list will be populated into the filteredUsers property. This following is the resultant screenshot:

Since PrimeFaces Version 4.0, we can specify the sortBy and filterBy properties as sortBy="emailId" and filterBy="emailId" instead of sortBy="#{user.emailId}" and filterBy="#{user.emailId}".

A couple of important tips

  • It is suggested to use a scope longer than the request such as the view scope to keep the filteredValue attribute so that the filtered list is still accessible after filtering.
  • The filter located at the header is a global one applying on all fields; this is implemented by calling the client-side API method called filter(). The important part is to specify the ID of the input text as globalFilter, which is a reserved identifier for DataTable.

Selecting DataTable rows

Selecting one or more rows from a table and performing operations such as editing or deleting them is a very common requirement. The DataTable component provides several ways to select a row(s).

Selecting single row

We can use a PrimeFaces' Command component, such as commandButton or commandLink, and bind the selected row to a server-side property using <f:setPropertyActionListener>, shown as follows:

<p:dataTable id="usersTbl" var="user" value="#{adminController.users}"> <!-- Column definitions --> <p:column style="width:20px;"> <p:commandButton id="selectButton" update=":form:userDetails"
icon="ui-icon-search" title="View">

<f:setPropertyActionListener value="#{user}"
target="#{adminController.selectedUser}" />
</p:commandButton> </p:column> </p:dataTable> <h:panelGrid id="userDetails" columns="2" > <h:outputText value="Id:" /> <h:outputText value="#{adminController.selectedUser.id}"/> <h:outputText value="Email:" /> <h:outputText value="#{adminController.selectedUser.emailId}"/> </h:panelGrid>

Selecting rows using a row click

Instead of having a separate button to trigger binding of a selected row to a server-side property, PrimeFaces provides another simpler way to bind the selected row by using selectionMode, selection, and rowKey attributes. Also, we can use the rowSelect and rowUnselect events to update other components based on the selected row, shown as follows:

<p:dataTable var="user" value="#{adminController.users}" selectionMode="single" selection=
"#{adminController.selectedUser}" rowKey="#{user.id}"> <p:ajax event="rowSelect" listener=
"#{adminController.onRowSelect}" update=":form:userDetails"/> <p:ajax event="rowUnselect" listener=
"#{adminController.onRowUnselect}" update=":form:userDetails"/>
<!-- Column definitions --> </p:dataTable> <h:panelGrid id="userDetails" columns="2" > <h:outputText value="Id:" /> <h:outputText value="#{adminController.selectedUser.id}"/> <h:outputText value="Email:" />
<h:outputText value="#{adminController.selectedUser.emailId}"/> </h:panelGrid>

Similarly, we can select multiple rows using selectionMode="multiple" and bind the selection attribute to an array or list of user objects:

<p:dataTable var="user" value="#{adminController.users}" selectionMode="multiple" selection=
"#{adminController.selectedUsers}" rowKey="#{user.id}"
> <!-- Column definitions -->
</p:dataTable>

rowKey should be a unique identifier from your data model and should be used by DataTable to find the selected rows. You can either define this key by using the rowKey attribute or by binding a data model that implements org.primefaces.model.SelectableDataModel.

When the multiple selection mode is enabled, we need to hold the Ctrl or command key and click on the rows to select multiple rows. If we don't hold on to the Ctrl or command key and click on a row and the previous selection will be cleared with only the last clicked row selected. We can customize this behavior using the rowSelectMode attribute. If you set rowSelectMode="add", when you click on a row, it will keep the previous selection and add the current selected row even though you don't hold the Ctrl or command key. The default rowSelectMode value is new. We can disable the row selection feature by setting disabledSelection="true".

Selecting rows using a radio button / checkbox

Another very common scenario is having a radio button or checkbox for each row, and the user can select one or more rows and then perform actions such as edit or delete.

The DataTable component provides a radio-button-based single row selection using a nested <p:column> element with selectionMode="single":

<p:dataTable var="user" value="#{adminController.users}"
selection="#{adminController.selectedUser}" rowKey="#{user.id}"> <p:column selectionMode="single"/> <!-- Column definitions --> </p:dataTable>

The DataTable component also provides checkbox-based multiple row selection using a nested <p:column> element with selectionMode="multiple":

<p:dataTable var="user" value="#{adminController.users}"
selection="#{adminController.selectedUsers}" rowKey="#{user.id}"> <p:column selectionMode="multiple"/> <!-- Column definitions --> </p:dataTable>

In our TechBuzz application, the administrator would like to have a facility to be able to select multiple users and disable them at one go. Let us see how we can implement this using the checkbox-based multiple rows selection.

PrimeFaces Beginner's Guide Get your JSF-based projects up and running with this easy-to-implement guide on PrimeFaces with this book and ebook
Published: November 2013
eBook Price: $29.99
Book Price: $49.99
See more
Select your format and quantity:

Time for action – using DataTable with multiple row selection support

In this section, we will demonstrate how to select multiple user rows and disable the selected users.

Create a DataTable component with the multiple row selection mode enabled, using the following code:

<p:dataTable
var="user" value="#{adminController.users}" selection="#{adminController.selectedUsers}" rowKey="#{user.id}"> <p:column selectionMode="multiple"/> <p:column headerText="Id" width="20px;"> <h:outputText value="#{user.id}" /> </p:column> <p:column headerText="Email" > <h:outputText value="#{user.emailId}" /> </p:column> <f:facet name="footer">
<p:commandButton value="Disable" actionListener=
"#{adminController.disableSelectedUsers}"/>
</f:facet> </p:dataTable>

What just happened?

We have created a DataTable component with multiple row selection support by using a nested <p:column> with selectionMode="multiple", which displays a checkbox for each row to select.

Using row expansion feature

A row can be expanded to display detail content using a row expansion column and the expansion facet. The <p:rowToggler> component places an expand/collapse icon, clicking on a collapsed row loads expanded content with AJAX.

Let us see how to use the row expansion feature of DataTable:

<p:dataTable var="user" value="#{adminController.users}"> <p:column style="width:15px;">
<p:rowToggler /> </p:column> <p:column headerText="Email" > <h:outputText value="#{user.emailId}" /> </p:column> <p:rowExpansion> ""<h:panelGrid columns="2"> <h:outputText value="FirstName: " /> <h:outputText value="#{user.firstName}" /> <h:outputText value="Disabled: " /> <h:outputText value="#{user.disabled}" /> </h:panelGrid> </p:rowExpansion> </p:dataTable>

The preceding code renders a DataTable component with the row expansion feature as follows:

We can make the rows expanded by default by setting the expandedRow attribute to true.

It is a very common mistake that many developers forget to add <p:rowToggler>. Without <p:rowToggler>, the DataTable row toggling doesn't work.

Using inline row editing feature

The DataTable component supports inline editing of data in row- and cell-based editing modes. Row-based editing is the default mode. For inline row/cell editing, the input and output facets are used to display data as labels in the output mode and as input components in the input mode. For the row-based editing mode, DataTable provides the rowEdit and rowEditCancel AJAX events to handle the save and cancel actions on the edited row data.

Time for action – using DataTable with row editing support

Let us see how to use the DataTable component row editing feature:

  1. Create a DataTable component with the editable mode enabled by setting editable to true:

    <p:dataTable id="usersTbl" var="user" value="#{adminController.users}"
    editable="true"> <p:ajax event="rowEdit" listener="#{adminController.onEdit}"/> <p:ajax event="rowEditCancel" listener="#{adminController.onCancel}"/> <p:column headerText="Email"> <h:outputText value="#{user.emailId}" /> </p:column> <p:column headerText="FirstName"> <p:cellEditor> <f:facet name="output"> <h:outputText value="#{user.firstName}" /> </f:facet> <f:facet name="input"> <p:inputText value="#{user.firstName}"/> </f:facet> </p:cellEditor> </p:column> <p:column headerText="Disabled"> <p:cellEditor> <f:facet name="output"> <h:outputText value="#{user.disabled}" /> </f:facet> <f:facet name="input"> <h:selectOneMenu value="#{user.disabled}" > <f:selectItem itemLabel="True" itemValue="true"/> <f:selectItem itemLabel="False" itemValue="false"/> </h:selectOneMenu> </f:facet> </p:cellEditor> </p:column> <p:column style="width:6%"> <p:rowEditor /> </p:column> </p:dataTable>

  2. Implement the rowEdit and rowEditCancel events listener methods:

    public void onEdit(RowEditEvent event) { User user = (User) event.getObject(); FacesMessage msg = new FacesMessage("Edited User Id : "+ user.getId()); FacesContext.getCurrentInstance().addMessage(null, msg); } public void onCancel(RowEditEvent event) { User user = (User) event.getObject(); FacesMessage msg = new FacesMessage
    ("Editing Cancelled for User Id: "+ user.getId()); FacesContext.getCurrentInstance().addMessage(null, msg); }

What just happened?

We have created DataTable with row editing enabled by setting editable="true". The columns that we want to edit were wrapped in <p:cellEditor> with the output facet to display as label and the input facet to display as the input element. We have used the <p:rowEditor> component to display row edit icon. When the edit icon is clicked, the row switches to the edit mode and it shows the save and cancel icons to save or cancel the changes made to that row. When the save icon is clicked on, the rowEdit event listener method, onEdit(), will be invoked and if you click on cancel icon, the rowEditCancel event listener method, onCancel(), will be invoked. A screenshot of the functioning is shown as follows:

Using the cell editing feature

As mentioned earlier, DataTable also supports the cell-based editing mode. In this mode, a cell switches to the edit mode when it is clicked on; losing focus triggers the cellEdit AJAX event, which saves the change value.

Time for action – using DataTable with cell-editing support

Let us see how to use the cell editing feature of DataTable:

  1. Create a DataTable component with the editable mode enabled by setting editable to true and editMode to cell, as shown in the following code:

    <p:dataTable id="usersTbl" var="user" value="#{adminController.users}"
    editable="true" editMode="cell"> <p:ajax event="cellEdit" listener="#{adminController.onCellEdit}"/> <p:column headerText="FirstName"> <p:cellEditor> <f:facet name="output"> <h:outputText value="#{user.firstName}" /> </f:facet> <f:facet name="input"> <p:inputText value="#{user.firstName}"/> </f:facet> </p:cellEditor> </p:column> </p:dataTable>

  2. Implement the cellEdit AJAX event listener method, onCellEdit():

    public void onCellEdit(CellEditEvent event) { Object oldValue = event.getOldValue(); Object newValue = event.getNewValue(); if(newValue != null && !newValue.equals(oldValue)) { FacesMessage msg = new FacesMessage
    ("Cell Changed :"+ "Old: " + oldValue + ", New:" + newValue); FacesContext.getCurrentInstance().addMessage(null, msg); } }

What just happened?

We have created a DataTable component with the cell-based editing mode enabled by setting editMode to cell. When an editable cell is clicked on, it switches to the editable mode and on loosing focus, it saves the edited value and invokes the cellEdit event listener method, onCellEdit().

Loading data leisurely

At times we may need to work with huge volumes of data where in you can't load the whole data into memory and display it. In those cases, we might want to load a subset of data in a page-by-page manner lazily.

DataTable supports loading data lazily by using org.primefaces.model.LazyDataModel as the data provider and setting lazy ="true". We need to implement a custom model object by extending org.primefaces.model.LazyDataModel and implement the load() method to fetch page data that satisfies the sorting and filtering criteria applied on the DataTable.

public List<User> load(int first, int pageSize,
String sortField, SortOrder sortOrder, Map<String,String> filters) { // code to fetch data based on applied sorting/filters }

Here, the load() method parameters represents:

  • first: This specifies the index of the first row to display
  • pageSize: This specifies the number of the rows to load on the page
  • sortField: This specifies the name of the sort field, for example, "firstName" for sortBy="#{user.firstName}"
  • sortOrder: This is an enumeration of type org.primefaces.model.SortOrder; could be either ASCENDING or DESCENDING
  • filter: A map with field names as keys (for example, "id" for filterBy="#{user.id}") and their corresponding filter values

Time for action –loading the DataTable data leisurely

Let us see how to use DataTable with the lazy loading feature.

  1. Create a DataTable component with the LazyDataModel binding and set the lazy attribute to true, as shown in the following code:

    <p:dataTable id="usersTbl" var="user"
    value="#{adminController.lazyUserModel}"
    paginator="true" rows="10" lazy="true">
    <p:column headerText="Id" sortBy="#{user.id}" > <h:outputText value="#{user.id}" />
    </p:column> <p:column headerText="FirstName" filterBy="#{user.firstName}"
    sortBy="#{user.firstName}"> <h:outputText value="#{user.firstName}" /> </p:column> </p:dataTable>

  2. Implement LazyUserModel by extending LazyDataModel to load data lazily:

    import org.primefaces.model.LazyDataModel; import org.primefaces.model.SortOrder; public class LazyUserModel extends LazyDataModel<User> { public User getRowData(String rowKey) { return loadUserFromDBByUserId(rowKey); } public Object getRowKey(User user) { return user.getId(); } public List<User> load(int first, int pageSize, String sortField,
    SortOrdersortOrder, Map<String,String> filters) { //get the count of total no. of records with filters applied int dataSize = getTotalRecordsCount(); this.setRowCount(dataSize); //load pageSize rows starting from index
    first by applying sorting and filters from datasource List<User> data = loadDataFromDB(); return data; } }

What just happened?

We have created a DataTable component with lazy loading feature by setting lazy to true and binding the property to LazyDataModel object. In load() method, we load only a subset(page) of data that satisfies the applied filters and sorting.

Using the column grouping support

Grouping is defined by the ColumnGroup component used to combine the DataTable header and footers.

In TechBuzz application, the administrator would like to see the statistics of tag-wise posts count, last year and current year. Let us see how we can use the DataTable Grouping feature to implement this screen.

Create a DataTable component and display header and footer using ColumnGroups:

<p:dataTable var="tagStats" value="#{adminController.tagStatisticsList}"> <f:facet name="header"> Tag Usage Statistics </f:facet> <p:columnGroup type="header"> <p:row> <p:column rowspan="2" headerText="Tag" /> <p:column colspan="2" headerText="Posts Associated with Tag" /> </p:row> <p:row> <p:column headerText="Last Year" /> <p:column headerText="This Year" /> </p:row> </p:columnGroup> <p:column headerText="Tag"> <h:outputText value="#{tagStats.tag}" /> </p:column> <p:column headerText="Posts Count"> <h:outputText value="#{tagStats.postsCountLastYear}" /> </p:column> <p:column headerText="Posts Count"> <h:outputText value="#{tagStats.postsCountThisYear}" /> </p:column> <p:columnGroup type="footer"> <p:row> <p:column style="text-align:right" footerText="Totals:"/> <p:column style="text-align:left" footerText="
#{adminController.lastYearPostsCount}" />
<p:column style="text-align:left" footerText="
#{adminController.thisYearPostsCount}" />
</p:row> </p:columnGroup> </p:dataTable>

The result is shown in the following screenshot:

The DataTable component also provides various other features such as scrolling, frozen rows, conditional coloring, resizable columns, and column reordering.

Using the scrolling feature

DataTable supports client and live scrolling. In the client mode, whole data is rendered, by enabling the liveScroll option, the data is loaded during scrolling. To enable scrolling, we need to set scrollable="true" and use the scrollHeight and scrollWidth attributes to specify scroll viewport height and width.

<p:dataTable id="usersTbl"
var="user" value="#{adminController.users}"
scrollable="true" scrollHeight="150" scrollWidth="400">
</p:dataTable>

By enabling liveScroll, the data will be loaded while scrolling using AJAX. We can specify the number of rows to load on a live scroll using the scrollRows attribute, as shown in the following code:

<p:dataTable var="user"
value="#{adminController.users}" scrollable="true" scrollHeight="150"
liveScroll="true" scrollRows="25"> … </p:dataTable>

Using the frozenRows feature

Sometimes we may want some rows to be displayed as sticky rows while scrolling. We can specify the rows to be displayed as sticky using the frozenRows attribute:

<p:dataTable var="user" value="#{adminController.users}"
scrollable="true" scrollHeight="150"
frozenRows="#{adminController.frozenUsers}"> .. </p:dataTable>

Applying custom styles for rows

We can apply custom styles conditionally using the rowStyleClass attribute. Suppose we want to display users in red color if the user status is disabled:

<p:dataTable var="user" value="#{adminController.users}"
rowStyleClass="#{user.disabled eq
true ? 'disabledUser':null}"
> </p:dataTable> <style type="text/css"> .disabledUser { background-color: #FF0000; color: #FFFFFF; } </style>

Using the resizable and draggable columns feature

By default, DataTable columns are not resizable and columns can't be reordered. We can make columns resizable by setting the resizableColumns attribute to true. By setting draggableColumns="true", we can rearrange the column order by dragging-and-dropping column headers:

<p:dataTable var="user" value="#{adminController.users}"
draggableColumns="true" resizableColumns="true"> </p:dataTable>

The column order is preserved in postbacks and the colReorder event is available as an AJAX event.

PrimeFaces Beginner's Guide Get your JSF-based projects up and running with this easy-to-implement guide on PrimeFaces with this book and ebook
Published: November 2013
eBook Price: $29.99
Book Price: $49.99
See more
Select your format and quantity:

Displaying data in the grid layout using the DataGrid component

The DataGrid component can be used to display collection of data in the grid layout along with pagination support.

Let us see how we can use the DataGrid component to display user details in a grid layout using pagination, displaying five users per page:

<p:dataGrid var="user" value="#{adminController.users}" columns="3" rows="5" paginator="true" rowsPerPageTemplate="5,10,15"> <p:panel header="#{user.firstName} #{user.lastName}" style="text-align:center"> <h:panelGrid columns="1"> <h:outputText value="#{user.id} : #{user.emailId}" /> </h:panelGrid> </p:panel> </p:dataGrid>

The preceding code displays DataGrid as shown in the following screenshot:

As we have specified columns="3" and rows="5", DataGrid displayed five items arranged in three columns resulting in two rows. Here, rows represent the number of items to be displayed per page, not the actual number of rows in DataGrid.

Exporting data into PDF/XLS/XML/CSV formats using the DataExporter component

The DataExporter component provides the ability to export the DataTable data into various formats such as Excel, PDF, CSV, and XML. DataExporter provides options for exporting:

  • Entire DataTable rows
  • Only current page rows
  • Only selected rows
  • Exclude particular columns
  • Customize exporting data using pre- and post-processors

To export data into PDF and Excel formats, we need itext.jar and apache-poi.jar respectively to be added to classpath:

<dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>3.7</version> </dependency> <dependency> <groupId>com.lowagie</groupId> <artifactId>itext</artifactId> <version>2.1.7</version> </dependency>

The basic usage of DataExporter is as follows:

<p:dataTable id="usersTbl" var="user" value="#{adminController.users}"> //columns </p:dataTable> <p:commandButton value="Export to Excel" ajax="false"> <p:dataExporter type="xls" target="usersTbl" fileName="users"/> </p:commandButton>

The DataExporter component provides the following attributes to customize its behavior:

  • type: This specifies the export type. Valid values are xls, pdf, csv, and xml.
  • target: This is the ID of the DataTable whose data to export.
  • fileName: This is the filename of the generated export file, defaults to the DataTable ID.
  • encoding: This specifies the character encoding to use. The Default is UTF-8.
  • pageOnly: When set, it exports only the current page instead of the whole dataset. The default value is false.
  • selectionOnly: When enabled, only the selection would be exported. The default value is false.
  • preProcessor: This specifies the preprocessor method expression for the exported document.
  • postProcessor: This specifies postprocessor method expression for the exported document.

Time for action – using DataExporter to export data into XLS and PDF formats

Let us see how we can use various features of DataExporter such as exporting whole dataset, exporting only current page, and excluding some columns:

  1. Create a DataTable and a DataExporter component to export all the data, only page data, and register pre- and post-processors for XLS and PDF exporters:

    <p:dataTable id="usersTbl" var="user"
    value="#{adminController.users}"
    rowKey="#{user.id}" paginator="true" rows="10">
    <p:column headerText="Id"> <f:facet name="header"> <h:outputText value="Id" /> </f:facet> <h:outputText value="#{user.id}" /> </p:column> <p:column> <f:facet name="header"> <h:outputText value="Email" /> </f:facet> <h:outputText value="#{user.emailId}" /> </p:column> <p:column exportable="false"> <f:facet name="header"> <h:outputText value="Disabled" /> </f:facet> <h:outputText value="#{user.disabled}" /> </p:column> </p:dataTable> <h:panelGrid columns="2"> <p:panel header="Export All Data"> <h:commandLink> <p:graphicImage value="/resources/images/excel.png"/> <p:dataExporter type="xls" target="usersTbl" fileName="users"
    postProcessor="#{adminController.postProcessXLS}" />
    </h:commandLink> <h:commandLink> <p:graphicImage value="/resources/images/pdf.png"/> <p:dataExporter type="pdf" target="usersTbl" fileName="users"
    preProcessor="#{adminController.preProcessPDF}"/>
    </h:commandLink> <h:commandLink> <p:graphicImage value="/resources/images/csv.png"/> <p:dataExporter type="csv" target="usersTbl" fileName="users" /> </h:commandLink> <h:commandLink> <p:graphicImage value="/resources/images/xml.png"/> <p:dataExporter type="xml" target="usersTbl" fileName="users"/> </h:commandLink> </p:panel> <p:panel header="Export Page Data"> <h:commandLink> <p:graphicImage value="/resources/images/excel.png"/> <p:dataExporter type="xls" target="usersTbl"
    fileName="users" pageOnly="true" />
    </h:commandLink> <h:commandLink> <p:graphicImage value="/resources/images/pdf.png"/> <p:dataExporter type="pdf" target="usersTbl"
    fileName="users" pageOnly="true"/>
    </h:commandLink> <h:commandLink> <p:graphicImage value="/resources/images/csv.png"/> <p:dataExporter type="csv" target="usersTbl"
    fileName="users" pageOnly="true"/>
    </h:commandLink> <h:commandLink> <p:graphicImage value="/resources/images/xml.png"/> <p:dataExporter type="xml" target="usersTbl"
    fileName="users" pageOnly="true"/>
    </h:commandLink> </p:panel> </h:panelGrid>

  2. Implement pre- and post-processor methods using the following code:

    public void postProcessXLS(Object document) { HSSFWorkbook wb = (HSSFWorkbook) document; HSSFSheet sheet = wb.getSheetAt(0); HSSFRow header = sheet.getRow(0); //perform operations on sheet/header etc } public void preProcessPDF(Object document) throws
    IOException, BadElementException, DocumentException { Document pdf = (Document) document; pdf.open(); pdf.setPageSize(PageSize.A4); //other operations on PDF }

What just happened?

We have created a DataTable component with the paginator support to display 10 rows per page. We have created two sets of DataExporter components, one to export whole data and another to export only current page data, into XLS, PDF, CSV, and XML formats. Note that we have used the exportable="false" attribute on the disabled <p:column> element and hence the disabled column data won't be exported. Also, we have registered preProcessor for PDF exporter and postProcessor for XLS exporter to manipulate the data before/after the exporting process.

A couple of important tips

  • To be able to export the column name headings, you should use the <f:facet name="header"> facets instead of <p:column headerText="...">.
  • As of PrimeFaces Version 4.0, pre- and post-processor support is available only for XLS and PDF exporters, but not for CSV or XML.

Summary

In this article, we have learned about data components, such as DataList and DataTable, along with various features such as pagination, sorting, filtering, lazy loading, and so on. Also, we have seen how to use DataExporter for exporting data into PDF, Excel, CSV, and XML formats.

Resources for Article:


Further resources on this subject:


About the Author :


K. Siva Prasad Reddy

K. Siva Prasad Reddy is a Senior Software Engineer living in Hyderabad, India, and having more than seven years of experience in developing enterprise applications with Java and JavaEE technologies. Siva is a Sun Certified Java Programmer and has a lot of experience in server-side technologies such as Java, JavaEE, Spring, Hibernate, MyBatis, JSF, PrimeFaces, and WebServices (SOAP/REST). Siva is also the author of Java Persistence with MyBatis 3, Packt Publishing.

Siva normally shares the knowledge he has acquired on his blog at www.sivalabs.in. If you want to find out more about his work, you can follow him on Twitter (@sivalabs) and GitHub (https://github.com/sivaprasadreddy).

Books From Packt


Instant PrimeFaces Starter [Instant]
Instant PrimeFaces Starter [Instant]

PrimeFaces Cookbook
PrimeFaces Cookbook

JBoss RichFaces 3.3
JBoss RichFaces 3.3

JBoss AS 5 Performance Tuning
JBoss AS 5 Performance Tuning

Mastering TypoScript: TYPO3 Website, Template, and Extension Development
Seam 2 Web Development: LITE

Apache MyFaces 1.2 Web Application Development
Apache MyFaces 1.2 Web Application Development

Apache MyFaces Trinidad 1.2: A Practical Guide
Apache MyFaces Trinidad 1.2: A Practical Guide

JSF 2.0 Cookbook
JSF 2.0 Cookbook


No votes yet

Post new comment

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
a
G
F
m
y
S
Enter the code without spaces and pay attention to upper/lower case.
Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software