One of the cool features of Oracle ADF is the ability to have inline components in RichTable (or tree) UI component. This post is based on the following "ADF Code Corner" example however in the example , they use binding layer . In my example – I don’t
Basically it looks like this
And alter you click on the small arrow icon , the row is expanded and you can see an inline data.
To get this feature is very easy, you only need to define a facet after column definition. In my case my inline data is just some text
<af:table value="#{bindings.customers.collectionModel}" var="row"
rows="#{bindings.customers.rangeSize}"
emptyText="#{bindings.customers.viewable ? 'No data to display.' : 'Access Denied.'}"
fetchSize="#{bindings.customers.rangeSize}" rowBandingInterval="0"
selectedRowKeys="#{bindings.customers.collectionModel.selectedRow}"
selectionListener="#{bindings.customers.collectionModel.makeCurrent}"
rowSelection="single" id="t1" binding="#{backingBeanScope.backing_untitled1.t1}">
<af:column sortProperty="#{bindings.customers.hints.customerName.name}" sortable="false"
headerText="#{bindings.customers.hints.customerName.label}" id="c1">
<af:outputText value="#{row.customerName}" id="ot1"/>
</af:column>
<af:column sortProperty="#{bindings.customers.hints.customerId.name}" sortable="false"
headerText="#{bindings.customers.hints.customerId.label}" id="c2">
<af:outputText value="#{row.customerId}" id="ot2"/>
</af:column>
<!-- This part will be an inline data -->
<f:facet name="detailStamp">
<af:outputText value="I am inner data" id="ot3"></af:outputText>
</f:facet>
</af:table>
You can access your delivery directly by providing tracking number inside GET parameter
https://www.fedex.com/fedextrack/?tracknumbers=AAAAAA. So it is not a problem to concatenate instead of the AAAAA the real tracking number. But user don’t want to click on the arrow icon at the beginning of the the row, but directly on the column data.
So first of all we need to convert the text in the column from plain text to clickable link
We do it by replacing
<af:column sortProperty="#{bindings.customers.hints.customerId.name}" sortable="false"
headerText="Tracking number" id="c2">
<af:outputText value="#{row.customerId}" id="ot2"/>
</af:column>
By
<af:column sortProperty="#{bindings.customers.hints.customerId.name}" sortable="false"
headerText="Tracking number" id="c2">
<af:commandLink text="#{row.customerId}" id="cl2"
partialSubmit="true"
action="#{viewScope.managedBean1.onButtonCLick}">
</af:commandLink>
</af:column>
Note that the command link will perform partial submit and is bound to some viewscope bean.
We will define this bean immediately inside adfc-config.xml file.
We need to understand also how does table knows which row to expand and with to collapse.
It is also easy . Each table has a property called “DisclosedRowKeys”
This object holds the keys of the rows in the table. Row which has her key inside this object will be expanded , the rest of the rows will stay collapsed.
So lets define this object inside our bean and bind the table “DisclosedRowKeys” property to it
public class HelperBean
{
private RowKeySetImpl disclosedKeys = null;
public HelperBean()
{
super();
}
adf by default makes first row selected which means , it will be expanded. We don’t want this , so we delete “SelectedRowKeys” property
We also want our table to refresh after user clicks on the link by using PPP so we define table partialTrigger property to be the ID of the command link (which is cl2)
So our goal is by clicking on the link to add row’s key to discloser object.
As you saw above our command link is bound to a method inside the bean
public String onButtonCLick()
{
FacesContext fctx = FacesContext.getCurrentInstance();
UIViewRoot root = fctx.getViewRoot();
AdfFacesContext adfFacesContext =
AdfFacesContext.getCurrentInstance();
//clear disclosed RowKeys
disclosedKeys =null;
//PPR tree table
RichTable treeTable =
(RichTable)root.findComponent("t1");
getDisclosedKeys();
adfFacesContext.addPartialTarget(treeTable);
return null;
}
We find the table , call getDisclosedKeys(); method and refresh the table. The key here is
getDisclosedKeys(); method.
In the original article (I posted the link at the beginning of this article), they use binding layer to find which row to expand. Since I always want to expand only current row, I don’t need an access to the binding
Here it is
public RowKeySetImpl getDisclosedKeys()
{
FacesContext fctx = FacesContext.getCurrentInstance();
UIViewRoot root = fctx.getViewRoot();
RichTable tree = (RichTable)root.findComponent("t1");
RowKeySet rks = tree.getSelectedRowKeys();
Key currentKey = null;
Iterator rksIter = rks.iterator();
while (rksIter.hasNext())
{
List l = (List) rksIter.next();
currentKey = (Key)l.get(0);
}
if (rks.size()>0) {
disclosedKeys = new RowKeySetImpl();
//if tree is found .... ADF CODE CORNER
if (tree != null) {
ArrayList newKeys = new ArrayList();
ArrayList temp = new ArrayList();
temp.add(0,currentKey);
newKeys.add(temp);
disclosedKeys.addAll(newKeys);
}
}
else
{
disclosedKeys = new RowKeySetImpl();
}
return disclosedKeys;
}
What it does?
1. Find the table
2. Get selected row (for this your table has to be set to enable selection)
3. Get the key of the row
4. Add the key to disclosure object. (There are a lot of ArrayLists, I know)
Now we will do some cosmetic changes.
Lets stretch the last column , so the table will occupy the whole page width
And also our facet will hold an iframe element instead of just output text
<f:facet name="detailStamp">
<af:inlineFrame source="https://www.fedex.com/fedextrack/?tracknumbers=#{row.trackingId}"
id="if1"></af:inlineFrame>
</f:facet>
I concatenate the binding of the tracking number to FedEx tracking link. This is what we get
User clicks on the tracking number link and see his delivery state immediately as an inline compoment