Thursday, January 13, 2005

Creator: How To Highlight Specific Data Table Rows

WARNING: This blog entry was imported from my old blog on blogs.sun.com (which used different blogging software), so formatting and links may not be correct.




screenshot of data table with highlighted row


This question came up in the forum:

How can you highlight particular rows or cells in a database table
based on business logic? For example, in the screenshot on the right,
I've highlighted the name of any rows where the job title is equal to "CEO".



First, you'll want to use CSS style classes; set up one style class
for normal rows, and another for
rows or cells to be highlighted. Add something like this to your page's
stylesheet (it's in the Resources folder):


.normal {
}

.highlighted {
color: red;
font-weight: bold
}



Next, you'll want to use value binding to tie the styleClass
property for items in the data table to some property which will return the
right style class to use for each cell.



Let's say you drop a Data Table component, and then drop the "PERSON"
table (from the sample "Travel" database bundled with Creator) on that
Data Table. Voila, you get a table populated with PERSONID, NAME, JOBTITLE
and one other row that I deleted by using the Table Layout item in the
context menu.



Next let's create the property we'll bind the styleClass to.
Go to the page bean (by for example double clicking on the page background),
position the caret in between some of the methods, right click and select
Add Property, leave all the defaults (so you're creating a String
property), and name it something like "nameStyle". This will create
a method name getNameStyle() which you now need to implement
such that it returns the String style class name "highlighted" or "normal"
depending on which row is being rendered when the method is called.



The conceptual difficulty in creating a property to return the
right style class
name to use is that a property accessor is a simple getter without
arguments -- you don't have
a "parameter" to tell you which row is being rendered when your method
is called. Here's the trick:


public String getNameStyle() {
Object o = getValue("#{currentRow['JOBTITLE']}");
if ("CEO".equals(o)) {
return "highlighted";
} else {
return "normal";
}
}


There are two things to notice:

  1. You can evaluate expression language statements from your Java
    code by calling getValue()
  2. You can consult #{currentRow to get the database row
    values for the current row being rendered in the table


If you click on the output text components in the data table (not the
ones in the header), you'll see that the above expression,
#{currentRow['JOBTITLE']}, is precisely what the JOBTITLE
column's Output Text component is bound to. Just like the component's
renderer, we can find the data for the current row, and then apply any
logic we want to it - here's it's as simple as checking if it's equal
to "CEO", but you could evaluate multiple different fields, including
ones not shown in the Data Table, and apply various logic to decide which
style class to return. And note that there's nothing requiring you to
limit yourself to two style classes, and you can highlight any number
of rows, not just one.




screenshot of property binding


The way you bind the styleClass property to for example the
Name column is to locate the output text in the Name column (not the
one in the header, the second one), right click on it, and choose
Property Bindings. That should give you a dialog like the one
on the right (click to enlarge). On the left, choose the
styleClass property, and on the right, drill into Page1 and
locate your new property, nameStyle. Don't forget to hit
Apply when you're done - it's a little unintuitive.



TIP: The expression language syntax is explained in a help document
that ships with Creator (as of one of the recent patches). Just go
to the Help menu, select Help Contents, click on Search, and type
"Expression"; for me the top topic returned is the one you want - titled
"JavaServer Faces Expression Language".





12 comments:

  1. Tor:
    Your examples on your Weblog are very helpful. I have a question about to highlight specific rows...your example works fine for strings, however when I use numbers I run into all types of troubles...below is my code which works fine for identifying if 23 is in the row...what I would like to know is how to do greater than or =, as well as less than or =:
    public String getNameStyle() {
    Object o = getValue("#{currentRow['TotalPoint']}");
    Integer i = new Integer(23);
    if (o.equals(i)) {
    return "highlighted";
    }
    else { return "normal";
    }
    Thanks in advance...I will publish this in the forum and see if I can get an answer as well. Thanks

    ReplyDelete
  2. Hi,
    I don't understand where the getVaule(String) comes from? Can you explain to me what it does?

    ReplyDelete
  3. If you look at your page bean (the Java class) you'll see that it extends a class (you can go to it, press Alt-G if I remember correctly when the caret is in the class name). It in turn extends another class - FacesBean.
    These classes provide a lot of convenience methods to your java code, so your own code is simple. getValue() is implemented there - you can see exactly what it does.
    I just now see Mark's question above - sorry I missed it below. What you want to do is call intValue() on the Integer objects. So in your example, yuo'd so if (i.intValue() > 23)) ...
    Hope that helps.

    ReplyDelete
  4. thanks for replying Tor.
    The problem is I'm not using Sun Creator; I'm using websphere..that's why i don't know where the getValue() come from.
    Is getValue() inside back-bean of a jsp file?
    Can you show me getValue()'s code?
    Thank you for your time and assistance..

    ReplyDelete
  5. Hi Tommy,
    let's make a deal.
    I'll tell you how to do this, if you will tell me the top 5 reasons why you chose to use WebSphere instead of Creator (getting feedback from people who chose to use another tool is always very valuable.)
    Ok, here's how you do it:
    protected Object getValue(FacesContext context, String expr) {
    ValueBinding vb = context.getApplication().createValueBinding(expr);
    return vb.getValue(context);
    }
    You find the FacesContext by FacesContext.getCurrentInstance().

    ReplyDelete
  6. Hi Tor,
    sorry i'm a noob in JSF ( and in speaking english, too )...
    I'm trying to hide one specified row in a DataTable.
    For example :
    <h:dataTable var="x" value="... >
    if the property called show of the object "x" is false, i dont want to show this row.
    I don't know how to do this, because if i use the rendered Attribute auf h:column JSF renderes only
    a "<tr></tr>" and this doesn't work.
    All i want is, that this "<tr></tr>" doesn't appear in my table.
    Do u hava any ideas how to managed that?

    ReplyDelete
  7. Oh, sorry
    every code i've written didn't appear...

    ReplyDelete
  8. Hi Tor,
    is there a way to do the same with a
    com.sun.rave.web.ui.component.Table ?
    Thanks

    ReplyDelete
  9. Winston has posted a solution for that:
    http://blogs.sun.com/roller/page/winston?entry=setting_table_column_style

    ReplyDelete
  10. In order to get this to work, I had to use
    #currentRow.value['JOBTITLE']
    What's going on?
    Also, is there someplace that all the faces context variables are listed, or do I have to hunt through each component's doc to find out what they put in the context?

    ReplyDelete
  11. Hello Tor :)
    I was wondering if there could be a way of setting a new style class for an entire row... I'm currently using HtmlDataModel to get the selected row when deleting, but is it possible to know at which row the rendering iteration is at a current moment and return this row with HtmlDataModel's .getRow();, when the styleClass="#{myBean.nameStyle}" is called.
    Thanx in advance

    ReplyDelete
  12. Hi,
    I have a similar requirement.
    In the data-table , i want to diplay an UP/DOWN arrow to indicate an ASC/DESC sort,next to the field on which the data-table is sorted.
    Can this be accomplished by using the rendered attribute on the outputText.
    Please help.

    ReplyDelete