Data tables in JSF

Data table is one of the most advanced UI components provided by JSF. This component is used to represent data in a table form and can contain multiple rows and columns and optionally header, footer and caption. In this post I would like to explain how to use it to render a simple table like this:

jsfdatatable

Basic table

The usage of data table is pretty simple. First, the data table has to be defined using h:datatable element. This element should have at least two attributes to iterate through the data. The first one is value which should point to one of the following:

  • single object
  • array
  • instance of java.util.List
  • instance of java.sql.ResultSet
  • instance of javax.servlet.jsp.jstl.sql.Result
  • instance of javax.faces.model.DataModel

JSF iterates though every element of the object pointed by this attribute and assigns each element to the variable specified by the second attribute var. Later, the properties can be extracted from this variable and put into the table. Typically, the data provided to data table is in form of an array or a list. If the data references a single scalar object, only one row will be rendered which is not much useful.

Inside h:datatable element we should put as many h:column elements as there are individual columns. Each h:column element can contain several JSF components which will appear in a single cell of the table. The final structure of a simple table looks like this:

<h:datatable value="#{rows}" value="row">
  <h:column>
    <!-- components in the first column -->
    #{row.columnValue1}
  </h:column>
  <h:column>
    <!-- components in the second column -->
    #{row.columnValue2}
  </h:column>
  <!-- more columns -->
</h:datatable>

Facets

This simple data table can be extended to contain optional header, footer and caption using f:facet elements:

<h:datatable value="#{rows}" value="row"
    headerClass="headerClass1"
    footerClass="footerClass1"
    captionClass="captionClass1">
  <h:column>
    <f:facet name="header">
      <!-- first column header contents -->
    </f:facet>
    <f:facet name="footer">
      <!-- first column footer contents -->
    </f:facet>
    <!-- components in the first column -->
    #{row.columnValue1}
  </h:column>
  <h:column>
    <f:facet name="header">
      <!-- second column header contents -->
    </f:facet>
    <f:facet name="footer">
      <!--  second column footer contents -->
    </f:facet>
    <!-- components in the second column -->
    #{row.columnValue2}
  </h:column>
  <!-- more columns -->
  <f:facet name="caption">
    <!-- table caption contents -->
  </f:facet>
</h:datatable>

Facets for header and footer are placed inside h:column elements while the facet for caption is put directly inside h:datatable. Additionally, we can specify CSS classes to be used by a header (headerClass), footer (footerClass) and also a caption (captionClass) of the table. There is also captionStyle attribute which specifies inline style for a caption.

Styles for rows and columns

CSS styles for individual columns and rows can be defined using either columnClasses or rowClasses attributes of h:datatable respectively. Obviously, these attributes are mutually exclusive and should not be applied to the same table.

Both attributes contain a list of comma-separated CSS classes. The first CSS class is used for the first column/row, the second one for the second column/row and so on. If the number of CSS classes is less than the number of columns/rows in a table, the classes are used repeatedly for the next columns/rows. For example if we specify only two classes, the first one is used for odd columns/rows and the second one for even columns/rows.

To apply the CSS style to the whole table we can use standard style or styleClass attributes.

Sorting and paging

Element h:datatable does not provide any real support for sorting elements in columns or splitting data into multiple pages so it has to be done manually (e.g. by defining non-standard component or using appropriate database queries to sort data and fetch only a portion of it). It contains first and count attributes to show only a portion of rows but it is not very useful in practice especially for very large tables.

Example

Equipped with this knowledge we can create a table with list of all HTTP headers sent by a web browser to a server. The single row of the table is represented using following name-value class:

package com.example.jsfdatatable;

public class HeaderEntry {

    private String name;
    private String value;

    public HeaderEntry(String name, String value) {
        this.name = name;
        this.value = value;
    }

    public String getName() {
        return name;
    }

    public String getValue() {
        return value;
    }

}

The list of all HTTP headers (table rows) is fetched from HTTPServletRequest using getEntries() method:

package com.example.jsfdatatable;

import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.enterprise.context.RequestScoped;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.inject.Named;
import javax.servlet.http.HttpServletRequest;

@Named
@RequestScoped
public class Headers {

    private List<HeaderEntry> entries;
    
    @PostConstruct
    public void init() {
        entries = new ArrayList<>();
        ExternalContext context = FacesContext.getCurrentInstance().getExternalContext();
        HttpServletRequest request = (HttpServletRequest) context.getRequest();
        
        Enumeration<String> namesIt = request.getHeaderNames();
        while (namesIt.hasMoreElements()) {
            String name = namesIt.nextElement();
            Enumeration<String> valueIt = request.getHeaders(name);
            while (valueIt.hasMoreElements()) {
                String value = valueIt.nextElement();
                entries.add(new HeaderEntry(name, value));
            }
        }
    }
    
    public List<HeaderEntry> getEntries() {
        return entries;
    }
}

The whole JSF web page contains a table with two columns (Name and Value), header, footer and caption. We use rowClasses to apply separate styles for odd and even rows:

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html" 
      xmlns:f="http://java.sun.com/jsf/core">
    <h:head>
        <title>#{msgs.httpHeaders}</title>
        <h:outputStylesheet library="default" name="css/styles.css" />
    </h:head>
    <h:body>
        <h:dataTable value="#{headers.entries}" var="entry"
                     styleClass="table"
                     rowClasses="tableRowOdd, tableRowEven"
                     headerClass="tableHeader"
                     footerClass="tableFooter"
                     captionClass="tableCaption" >
            <h:column>
                <f:facet name="header">#{msgs.name}</f:facet>
                <f:facet name="footer">#{msgs.stopDash}</f:facet>
                <h:outputText value="#{entry.name}" />
            </h:column>
            <h:column>
                <f:facet name="header">#{msgs.value}</f:facet>
                <f:facet name="footer">#{msgs.stopDash}</f:facet>
                <h:outputText value="#{entry.value}" />
            </h:column>
            <f:facet name="caption">#{msgs.httpHeadersCaption}</f:facet>
        </h:dataTable>
    </h:body>
</html>

Conclusion

Element h:datatable is very useful in rendering HTML tables. While it does not provide any advanced features. it can be easily extended or used a part of bigger structure which provides such support.

Even though we used only plain text inside cells, they can actually contain more advanced components like graphics, radio buttons, check boxes, lists and so on.

The complete example was tested on JBoss AS 7.1 and is available at GitHub.

Advertisement

About Robert Piasecki

Husband and father, Java software developer, Linux and open-source fan.
This entry was posted in Java, Java EE, JSF and tagged , , , , . Bookmark the permalink.

4 Responses to Data tables in JSF

  1. Pingback: Facelets ui:repeat tag | softwarecave

  2. Pingback: Data tables in JSF | softwarecave | Best out of...

  3. Pingback: Data tables in JSF | softwarecave | Java Enterp...

  4. Walter L. says:

    Hi, thanks for your helpful examples. I’m guessing your first example should say “var” instead of “value” correct? I’m trying to figure out what “var” does on another site and ended up here.
    should probably be
    , right?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.