ICEFaces Tooltip and Data Table
Update: If you simply need to have a single tolltip for a single ice:column then simply include the tooltip along side the body like normal. If you need to reference a dynamic tooltip from multiple columns or if the tooltip needs to be external to the datatable, please keep reading
Making a panelToolTip work with a dataTable in ICEFaces can be non-trivial. The lack of good examples doesn’t help either. In this example we will show a table of “Things” that each have three fields. The table will only show fieldA and fieldB while the tooltip will show fieldC. Note that we treat fieldA like a key, i.e. it is unique among the items.
First let us define our Thing class as an inner static class to a backing bean like so…
static public class Thing { private String fieldA; private String fieldB; private String fieldC; public Thing(String fieldA, String fieldB, String fieldC) { super(); this.fieldA = fieldA; this.fieldB = fieldB; this.fieldC = fieldC; } /* getters */ } |
Next let’s define the dataTable which will show our array of Things, but it only shows field A and B…
<ice:dataTable value="#{tooltipTableExample.things}" var="thing" > <h:column> <f:facet name="header"> <ice:outputText value=""/> </f:facet> <ice:panelGroup panelTooltip=":::thingPanelToolTip"> <ice:outputText value="hover"/> <ice:outputText id="hoverID" style="display: none" value="#{thing.fieldA}" /> </ice:panelGroup> </h:column> <h:column> <f:facet name="header"> <ice:outputText value="Field A"/> </f:facet> <ice:outputText value="#{thing.fieldA}"/> </h:column> <h:column> <f:facet name="header"> <ice:outputText value="Field B"/> </f:facet> <ice:outputText value="#{thing.fieldB}"/> </h:column> </ice:dataTable> |
This is a standard dataTable with two key exceptions, both in the first column.
- The use of panelTooltip=”:::thingPanelToolTip”
- The use of an invisible outputText
Note that the panelTooltip does not appear in the dataTable. This is because the dataTable works on lists of data and the panelTooltip does not. That is, JSF would have a hard time figuring out which tooltip to use if the tooltip appeared in the dataTable since there would be one for each row.
Quick Tip: the :::Name syntax is used to tell JSF to look up the XML tree until it finds an ID that matches instead of just the current scope.
Next, define what the tooltip looks like…
<ice:panelTooltip id="thingPanelToolTip" displayListener="#{tooltipTableExample.tooltipDisplayListener}"> <f:facet name="header"> <ice:panelGroup> <ice:outputText value="Field C"/> </ice:panelGroup> </f:facet> <f:facet name="body"> <ice:panelGroup> <ice:outputText value="#{tooltipTableExample.hoveredThing.fieldC}"/> </ice:panelGroup> </f:facet> </ice:panelTooltip> |
Nothing too special here, but note the use of a display listener. The display listener gives the server a chance to figure out which Thing is being hovered.
Finally, the backing bean…
public class TooltipTableExample { /* things => "things" that the dataTable will show * fieldAtoStringMap => maps field A to a thing * hoverThingFieldA => the filed A of the hovered thing */ private Thing[] things; private Map fieldAtoStringMap; private String hoverThingFieldA; public TooltipTableExample() { things = new Thing[] { new Thing("1", "A", "X"), new Thing("2", "B", "Y"), new Thing("3", "C", "Z") }; /* build our map of fieldA => thing */ fieldAtoStringMap = new HashMap(); for (Thing t : things) { fieldAtoStringMap.put(t.getFieldA(), t); } } /* when the tooltip appears, this will get called */ public void tooltipDisplayListener(DisplayEvent event) { if (event.isVisible() == false) { /* if hiding tooltip do nothing */ return; } /* target is the component that is being hovered; in this * case, it's a panelGroup in the datatable */ for (UIComponent child : event.getTarget().getChildren()) { /* if the child's id matches our hard coded "holder" id * then set the current hover field A to it's value */ if ( child.getId().equals("hoverID") == true && child instanceof HtmlOutputText) { HtmlOutputText hot = (HtmlOutputText) child; this.setHoverThingFieldA(hot.getValue().toString()); return; } } } public Thing getHoveredThing() { return this.getFieldAtoStringMap().get(this.getHoverThingFieldA()); } /* getters and Thing class */ |
Most of the interesting stuff happens in the display listener, and the comments in the code are pretty good documentation. In short, this backing bean has an array of Things, a map of keys to things, and the ID of the currently hovered thing. The display listener will look for the hidden output text in the row and use that to set the currently selected thing.
I am sure there are better ways, but this is the simplest method I could come up with after searching the web for hours.
Feb 20, 2010aewhiteCategory: General, Programming Read more
Comments (4)
Tags: ICEFaces, Java

