Wednesday, 17 April 2013

Oracle ADF - programmatically expand row in RichTable to show detailsTamp

 

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

image

And alter you click on the small arrow icon , the row is expanded and you can see an inline data.

image

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>
Now the demand is the following . One of the table column actually displays the tracking number of the FedEx, so when user clicks on this column inline data will show the delivery status in FedEx web page.


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.


 


image


 


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”


image


 


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


image


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)


image


 


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


image


 


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


 


image


User clicks on the tracking number link and see his delivery state immediately as an inline compoment

1 comment: