ADF Faces – Server Side (partial page rendering) Column Hide and Seek – Expanding/Collapsing Columns in Table

Tables are probably the most important ADF Faces component to
present data to the end user. A table can present a huge amount of data
at once, both in terms of rows and columns. This of course can be
overwhelming. Frequently, only some of the columns – some of the fields
in the records – are really essential at all times. Other elements –
columns – are only required in special situations or in groups at a
time. 

When designing the page, there are several approaches to
such requirements. One is the Detail Disclosure, where the table
columns represent only those key data elements and every row in the
table can be disclosed (expanded) to show in line in the table the
other data elements. Others include the table overflow right or below –
where for the currently selected table row the data elements not shown
in the columns are presented in a single record block to the side or
bottom of the table. Yet another approach is a popup element that
appears for the current table row and presents the additional fields
not included in the table as columns. All these approaches share a
drive to reduce the complexity of the UI without sacrificing the user’s
ability to view all data relevant for a specific record in the table.
They also (except for the detail disclosure) have in common that the
additional fields are shown for only one record at a time. None of them
make it easy or even possible to sort on the fields that are not part
of the key set of columns.

In this article, we will discuss
yet another way for ADF Tables of making specific information available
when the user so desires – this time for all records at once. It is the
server side Column Disclosure, a PPR (partial page rendering) based way of expanding and
collapsing columns or groups of columns.

For example the
following page contains a table that shows Employees and their
Allocations on a project. For each employee, we only see a few details
(id, first name and last name). There is much more to know about
employees – email address, phone number, job title, salary, hiredate –
however that information is not frequently required. When it is
required, we typically want to compare the values (at least of Job,
Hiredate and Salary) of the employees – so we should see them all at
once.
 

ADF Faces - Server Side (partial page rendering) Column Hide and Seek - Expanding/Collapsing Columns in Table

Press
the Expand icon in the Employees header and the Employee Details are
expanded – client side, no server roundtrip, really fast (say
instantaneously):

ADF Faces - Server Side (partial page rendering) Column Hide and Seek - Expanding/Collapsing Columns in Table 

In
the rest of the article, we will discuss how we can implement this
functionality largely declaratively, leveraging the PPR (Ajax) infrastructure in ADF Faces.....
Another article will discuss a client side solution
(using java Script for hiding/displaying column clusters even faster than the solution presented in this article.

First of all, the purely visual side of things: by using nested af:column elements (as described in the article ADF Faces – Nested Columns),
it was simple to create the Employee and Employee Details column
clusters. I have added the collapse and expand icons to the Employee
Column header; these are the visible contents of two command links, that each initiate a partial page rendering cycle. The commandLinks each have a setActionListener child element that sets or resets the EmployeeDetails property on the ColumnClusterCollapseControllerBean managed bean.

The EmployeeDetails column has its rendered attribute referring to that same managed bean’s property: #{ColumnClusterCollapseControllerBean.EmployeeDetails}.

  <af:column>
<f:facet name="header">
<af:panelGroup>
<af:outputText value="Employee"/>
<af:commandLink partialSubmit="true"
rendered="#{!ColumnClusterCollapseControllerBean.EmployeeDetails}"
id="expandEmployeeDetails">
<af:objectImage source="/jheadstart/images/expandCurrent.gif"/>
<af:setActionListener from="#{true}"
to="#{ColumnClusterCollapseControllerBean.EmployeeDetails}"/>
</af:commandLink>
<af:commandLink partialSubmit="true"
rendered="#{ColumnClusterCollapseControllerBean.EmployeeDetails}"
id="collapseEmployeeDetails">
<af:objectImage source="/jheadstart/images/collapseCurrent.gif"/>
<af:setActionListener from="#{false}"
to="#{ColumnClusterCollapseControllerBean.EmployeeDetails}"/>
</af:commandLink>
</af:panelGroup>
</f:facet>
<af:column id="AllocationsEmpIdColumn" ...>
<f:facet name="header">
<af:outputLabel value="EmpId"/>
</f:facet>
...
</af:column>
<af:column id="AllocationsFirstNameColumn" ..>
<f:facet name="header">
<af:outputLabel value="FirstName"/>
</f:facet>
...
</af:column>
<af:column id="AllocationsLastNameColumn" ... >
<f:facet name="header">
<af:outputLabel value="LastName" .../>
</f:facet>
...
</af:column>
<af:column id="EmpDetails" ...>
<f:facet name="header">
<af:outputLabel value="Employee Details" .. />
</f:facet>
<af:column id="AllocationsEmailColumn"
...

The table needs to be refreshed whenever a column cluster is either collapsed or expanded. So the table should be part of the set of partial targets for the PPR cycles started by the two command links Expand and Collapse:

<af:table id="AllocationsTable" width="50%"
...
partialTriggers="AllocationsTable:expandEmployeeDetails AllocationsTable:collapseEmployeeDetails"
binding="#{AllocationsCollectionModel.table}">
 

The missing piece here is the managed bean ColumnClusterCollapseControllerBean that the collapse and expand links refer to and that the rendered property for the Employee Details column is based on. This managed bean’s definition in the faces-config.xml file:

    <managed-bean>
<managed-bean-name>ColumnClusterCollapseControllerBean</managed-bean-name>
<managed-bean-class>java.util.HashMap</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
<map-entries>
<key-class>java.lang.String</key-class>
<value-class>java.lang.Boolean</value-class>
<map-entry>
<key>EmployeeDetails</key>
<value>false</value>
</map-entry>
</map-entries>
</managed-bean>
 

So, implementing nested columns, column clusters and their expansibility and collapsibility is dead easy!