Implementing Cell Highlighting in JSF-based Rich Enterprise Apps (Part 1)

by Lucas Jellema ACE Director

Help your end-users digest information by implementing cell highlighting in your JavaServer Faces app.

Published November 2008

Data-oriented applications tend to swamp the end user with information. Rows and rows of data, although neatly organized in columns and cells, can be somewhat overwhelming. The significance of certain data records can frequently be made clearer by color highlighting cells. Different colors indicate different statuses for the records. The colors can make records that deserve special attention for whatever reason clearly stand out.

Tools such as Oracle Discoverer, Microsoft Excel, and Oracle Application Express provide facilities that allow the end user to specify filter criteria, which are then used for the color highlighting. This includes, for example, threshold highlighting where various value ranges are identified by specific colors: salaries less than 2000, between 2000 and 3000, and greater than 3000 have their own color assigned. Another type of highlighting is based on filter expressions: expressions such as JOB <> 'MANAGER and SAL > 3000 or JOB = 'CLERK' or SAL < 1500. Every filter expression can be associated with a color.

In this first in a series of two articles, you will see how such highlighting can be implemented in a JavaServer Faces (JSF) application, more specifically in Oracle Application Development Framework (ADF) Faces table components. You will learn, using Oracle ADF 11g Rich Faces as the JSF implementation, how to add user-controlled threshold or traffic light highlighting. The user specifies for each column that supports highlighting the threshold values as well as the colors to be used. Such settings are retained when requerying data and sorting the records. When data is changed, the highlighting is adjusted accordingly.

The second article in the series adds even more power for the end user: it describes how to add end-user functionality to dynamically add, update, and remove thresholds—supporting up to as many thresholds as could possibly be desired. It then goes beyond the simple threshold pattern to also provide expression-based filtering. The end user can set up one or multiple expressions that can refer to all attributes in the data records. The first expression a record satisfies will determine the color for the cell.

You will use a simple Oracle ADF Faces table page in this article. You can easily create it yourself, or download the ZIP file with the start situation. The latter approach has the advantage of not needing a database from which to retrieve the data.

Create the Starting Point Yourself (with Database)

Start Oracle JDeveloper. Create a new application using the Create Application dialog that you start by selecting File, New and selecting the Application item under category General. Choose the Web Application (JSF, ADF BC) template. The wizard will automatically create a Model and a ViewController project.

From the New Gallery, select the option (Business Tier, ADF Business Components) Business Components from Tables. Select, and if necessary first create, a database connection to the SCOTT schema in some database. Create an Entity Object Emp for table EMP and a default ViewObject EmpView for the Emp Entity. Call the application module HrmManager.

The default datatype used in Oracle ADF Business Components for columns with datatype NUMBER is oracle.jbo.domain.Number. This highly flexible, functionally rich type is not recognized by the EL engine in JSF. We therefore go to edit the Emp Entity Object and change the Type for the Sal attribute from Number to Double. Do the same thing for the Comm attribute. Finally, set the Deptno attribute's type to Integer.

When you look at the Data Control palette, you will see the EmpView collection in the HrmManager data control—exactly what we need to get started with your Web application.

Use the Provided Starting Point (No Database Needed)

Somewhat easier and equally instructive is to approach cell highlighting using the provided Oracle JDeveloper Application ADFCellHighlighting_StartingPoint. It contains a Model and ViewController project. The latter is empty; the former contains three classes: HrmManager, EmpManager (a singleton), and Emp. The Emp and EmpManager classes have been generated from the EMP table to produce an offline (no database) datasource. This blog entry explains in detail how this is done and also provides the code for generating such disconnected datasources from database tables.

The HrmManager class has been published as a DataControl. As a result, the empscollection is available on the Data Control palette.

Step 1: Create the EMP Table Page

Let's first create the JSF page to which weyouare going to apply cell highlighting. In the ViewController project, select (Web Tier, JSF) JSF JSP in the New Gallery. Call the new file EmpTable.jspx and click Finish.

An empty page is now displayed in the page editor. From the Data Control palette, drag either the EmpView collection (based on ADF BC and database) or the emps collection (under empManager, based on disconnected beans) and drop it as an ADF Table. In the Edit Table Columns dialog, specify the column order and prompt definitions seen in the following figure and enable sorting:

Figure
Figure 1 Edit Table Columns dialog

Click OK. The page editor displays. From the right mouse button menu, select Go to Page Definition. Change the rangeSize attribute on the EmpView iterator (ADF BC based) or the empsIterator accessorIterator (bean based) from 10 to -1 (in order to have all records displayed in the page).

Select Run from the right mouse button menu to see the page in action. At this point, you should see this page running in your browser. (Note: you might need to fiddle with the columns attribute for some of the inputText elements to get the proper width for all columns.):

Figure
Figure 2 Page with all records displayed

 

Step 2: Cell Highlighting Based on Static Thresholds

Your first step will be to add static cell highlighting to the EmpTable page. Focus on Salary cells. To quickly get insight into the distribution of salaries, you want to highlight salaries less than 1000 in green, greater than 3000 in red, and the others in light gray.

The easiest way of assigning colors to cells is through the contentStyle attribute on the inputText Sal element as follows:

contentStyle="background-color:#{(row.sal lt 1000)?'green':(row.sal gt 3000?'red':'lightgray')};"


Using a ternary expression inside the EL expression used for setting the CSS property background color, now specify that when row.sal—the value displayed in the current cell—is less than 1000, the expression should evaluate to green. Otherwise, the result should be the outcome of the nested expression that tests whether row.sal is greater than 3000. If it is, the result is red, or else the outcome is light gray.


Figure
Figure 3 Salary value highlighting

If you based your Data Control on the EmpView collection, rather than on the offline HrmManager bean, you need to change row.sal to row.Sal—with a capital S.

You can run the page and see the highlighting for the salaries. If you change salary values and then sort by clicking any column header, you will see the highlighting adjusted to the updated values:

Figure
Figure 4 Adjustments to the Salary values

 

Step 3: Allow Dynamic Threshold Values and Colors

The first step provided cell highlighting. However, the highlighting is very static—based on the hard-coded values 1000 and 3000 somewhere in the JSF page. Clearly not the most dynamic way to go about it. Let's replace those hard-coded threshold values with references to managed bean properties, which you can then allow our end user to manipulate.

First of all, change the contentStyle attribute in the inputText for Sal to

contentStyle="background-color:#{(row.Sal lt EmpThresholdHighlighter.lowThreshold)
        ?EmpThresholdHighlighter.lowAreaColor:
   (( row.Sal gt EmpThresholdHighlighter.highThreshold)
            ?EmpThresholdHighlighter.highAreaColor:EmpThresholdHighlighter.middleAreaColor)};"


Note: Use row.sal (lowercase S) when you are using a bean based data control.

You will notice that you have not only replaced the hard-coded threshold values with bean references, but you did the same for the colors. Instead of red and green, the expression now refers to EmpThresholdHighlighter.lowAreaColor and EmpThresholdHighlighter.highAreaColor.

The managed bean EmpThresholdHighlighter is configured in the adfc config.xml like this:


<managed-bean>
    <managed-bean-name>EmpThresholdHighlighter</managed-bean-name>
    <managed-bean-class>otn.cellhighlighting.jsf.ThreshholdHighlightBean</managed-bean-class>
    <managed-bean-scope>session</managed-bean-scope>
</managed-bean>

The class it is based on is just a JavaBean with five properties: lowThreshold, highThreshold, and the three colors: lowAreaColor, middleAreaColor and highAreaColor.

package otn.cellhighlighting.jsf;
public class ThreshholdHighlightBean {

    private Long lowThreshold = new Long(1000);
    private Long highThreshold = new Long(3000);

    private String lowAreaColor ="green";
    private String middleAreaColor ="lightgray";
    private String highAreaColor ="red";

    public ThreshholdHighlightBean() {
    }
... accessor methods (getters and setters) for all properties
}

You can now run the page and get the same results as at the end of step 1. The interesting bit comes when you allow the user to change the threshold values and the colors.


You need to add a panel to the page where the user can specify these values. Add the following showDetailHeader to the page, inserting it just below the table:

<af:showDetailHeader text="Highlight Settings for Employees Table"
                             disclosed="true"
                             inlineStyle="border-color:Gray; border-style:double; width:367px;">
              <af:panelFormLayout>
                <af:inputText label="Lower Threshold"
                              value="#{EmpThresholdHighlighter.lowThreshold}"/>
                <af:inputText label="High Threshold"
                              value="#{EmpThresholdHighlighter.highThreshold}"/>
                <af:objectSpacer width="10" height="10"/>
                <af:inputText label="Low Area Color"
                              value="#{EmpThresholdHighlighter.lowAreaColor}"/>
                <af:inputText label="Medium Area Color"
                              value="#{EmpThresholdHighlighter.middleAreaColor}"/>
                <af:inputText label="High Area Color"
                              value="#{EmpThresholdHighlighter.highAreaColor}"/>
              </af:panelForm>
            </af:panelHeader>
            <af:commandButton text="Apply Highlighting" partialSubmit="true"
                              id="doHighlight"/>
</af:showDetailHeader>


The commandButton doHighlight has the partialSubmit attribute set to "true". When the button is clicked, the settings in this panel are to be applied immediately. A partial page refresh can update the highlight settings in the table, if the table responds to the button press. That is the case when you add the button's ID to the partialTriggers attribute of the table:


<af:table value="#{bindings.EmpManageremps.collectionModel}" var="row"
                    partialTriggers="doHighlight"
                   ...
Now when you run the page, you can manipulate the threshold settings as well as the colors associated with the three areas: low, medium, and high.

Figure
Figure 5 Manipulating threshold settings and colors

 

Step 4: Use the Color Picker to Choose the Highlight Color

It seems somewhat strange to set the color by typing in the color name as specified in CSS terms, especially when Oracle ADF Faces has a color picker component. So let's now use that component for setting the colors in a more user-friendly way.

The value set by the color picker component is of type java.awt.Color. You need to modify the ThreshholdHighlightBean to cater to this. First, remove the existing color properties—lowAreaColor, middleAreaColor, highAreaColor—and their setter methods.

Then add these properties and generate their associated accessors:

    private Color lowColor = new Color(153, 255, 153); // greenish
    private Color middleColor = new Color(255, 255, 150); // yellow
    private Color highColor = new Color(255, 190, 190); // red

Implement getter methods getLowAreaColor, getMiddleAreaColor, and getHighAreaColor like this:

public String getLowAreaColor() {
        return this.lowAreaColor == null ? "" :
               "rgb(" + this.lowColor.getRed() + "," +
               this.lowColor.getGreen() + "," +
               this.lowColor.getBlue() + ")";
    }

Remove the three inputText elements. Now you need to add the color picker components to set the three threshold colors. Here is an example of the Low Area Color picker; the other two are similar:

<af:panelLabelAndMessage label="Low Area Color">
              <af:inputColor id="lowAreaColor" chooseId="chooseLow"
                             value="#{EmpThresholdHighlighter.lowColor}"
                             compact="true"/>
              <af:chooseColor id="chooseLow" defaultVisible="false"
                              lastUsedVisible="false"/>
</af:panelLabelAndMessage>

Note: The inputColor component displays the color currently set in its value attribute. It accepts new color selections made in the chooseColor component with the ID indicated by the chooseId attribute.


Now also add the color pickers for Medium Area Color and High Area Color. You could somewhat reorganize the Highlight Settings panel to cater for the size of the Choose Color components. One way of doing that is through the use of \ .

<af:panelGroupLayout layout="horizontal" valign="top">
      <af:panelFormLayout rows="2">
         ... the two inputText elements ...   
      </af:panelFormLayout>
      the three panelLabelAndMessage components with the inputColor & chooseColor
</af:panelGroupLayout>

When you next run the EmpTable page, you will see the Color Picker panel that enables easier selection of the highlight colors.

Figure
Figure 6 Color picker panel

 

Step 5: Highlight Settings in Pop-Up Panel

It is undeniably convenient for end users to be able to set up cell highlighting in their tables. However, the panel for highlighting settings takes up an awful lot of real estate on the page—and that is just for a single column. At the very least, we would like to be able to only bring up this panel when you need to inspect it or make changes to it, and have it otherwise not take up so much space. In this last step, you will introduce a pop-up panel that can be invoked from the Sal column header. This also prepares the way for cell highlighting for multiple columns. Multicolumn highlighting is a topic for the second part of this series, along with expression-based highlighting.

ADF 11g Rich Faces, among many other interesting things, gives us a real popup component. We will use this component to contain the cell highlighting controls in a panelWindow that is only displayed when explicitly invoked.

We add an icon to the Salary column header that can be clicked to bring up the popup. To achieve this, remove the headerText attribute on the column, add the header facet inside the column, and configure its contents as follows:

<af:column sortProperty="sal" sortable="true">
            <f:facet name="header">
              <af:panelGroupLayout layout="horizontal">
                <af:outputText value="#{bindings.emps.hints.sal.label}"/>
                <af:image shortDesc="Open Cell Highlight Settings Window"
                          source="/highlightIcon.gif">
                  <af:showPopupBehavior popupId=":CellHighlightThresholdSettings"
                                        triggerType="click"/>
                </af:image>
              </af:panelGroupLayout>
            </f:facet>

The showPopupBehavior child element inside the af:image is the key to bringing up the Popup window. It specifies through the triggerType attribute that when its parent, the icon, is clicked, the popup with id CellHighlightThresholdSettings should be displayed. The popup itself will replace the showDetailHeader container with all highlighting input components. Simply replace the showDetailHeader component with:

        <af:popup id="CellHighlightThresholdSettings">
          <af:panelWindow title="Highlight Settings for Employees Table">
... same contents as before
          </af:panelWindow>
        </af:popup>

You have now created a popup that contains a panelWindow. The popup is initially not displayed; it only appears when some action explicitly invokes it—such as clicking on the highlight icon in the column header.


When you now run the page, it will look like a very ordinary table page, except for the little icon in the Sal column header:

Figure
Figure 7 "Highlight" icon in Sal column header

Move the mouse over the highlight icon, and now the highlight settings panel will appear:

Figure
Figure 8 Highlight settings panel

The user can make the desired changes, and then click Apply Highlighting to make the table redisplay with all changes applied.

Conclusion

In this first of a two-part series on Oracle ADF cell highlighting, you have seen how we can rapidly add static highlighting to Oracle ADF Faces data tables. Using EL expressions, getting the highlighting to work was easy. You then extended the functionality with more end-user control: backed by a managed bean we made both the threshold values and the associated colors dynamic and provided the user with a panel to manipulate those settings. In the last step, you embedded this panel in the column itself. The panel will now only be displayed when the user needs it, making for a much better usable user interface.

Part 2 extends the highlight functionality in several ways. You will add support for multicolumn highlighting in the same table, enabling the Hiredate column to be highlighted based on experience (green being less experienced obviously) and the Salary column indicating the income category for the employee. You will also allow for dynamic threshold definitions: users can add as many thresholds as they see fit, instead of the two supported in this installment. Finally, and most interestingly, is the addition of expression-based highlighting. Cells can be highlighted based on formulas that can refer to all attributes in a record (even nondisplayed ones).

 Read Part 2 of this series



Lucas Jellema is CTO of AMIS in Nieuwegein, The Netherlands, and an Oracle ACE Director (Developer Tools). He participates in projects typically involving ADF and SOA. In addition he is a frequent presenter at conferences like Oracle OpenWorld and JavaOne as well as a frequent blogger.