Skip to main content

Layout Tips - Organizing page content using <trh:tableLayout>

ADF Faces is packaged along with rich set of layout components which can be used to arrange other components on a page. Though these components are smart enough to meet most of your requirement, sometimes you may need to look around for other layout components to realize specific UI features. This discussion is based on such a scenario where I'm using <trh:tableLayout> for building certain part of the UI. btw, this post is in (logical) continuation of my previous post on Layout Tips - Stretching components....

In this post, I'm discussing a UI centric use case implementation using ADF Faces layout components along with MyFaces Trinidad <trh:tableLayout>. Though mixing of the components from these two families are not considered as good practice, sometimes you may need to move out of the box to make your application working :)

A Case Study

Requirement is to build a web page as shown in following screen shot.


In my experience, the painful phase of UI design is picking up the right layout component which works for a specific case. Let me share simple tip to make your life easier. To begin with, let us draw outlines over the screen elements as shown in the following diagram. You can follow this approach irrespective of the technology you are using for building the UI. I was using this approach for building Java Swing UI when I started my career ;)

Now the picture is more clear, the dark clouds are moving out and the silver lining is becoming visible :) The requirement here is that table component is expected to stretch to fit the available space in the browser window and the 'parameter form' displayed below should occupy fixed height and width.

Cool...now we may need to identify the right set of layout components to organize the page contents. One obvious candidate for top level container is panelStretchLayout component. This component stretches the child in the center facet to fill all of available space. So let us add table to center facet of the panelStretchLayout, and specify fixed height for bottom facet where the parameter from goes. The jsf page may look like as follows.

 <af:panelStretchLayout id="psl1" startWidth="50px"
                                   bottomHeight="100px">
  <f:facet name="center">
     <af:table value="#{bindings.EmployeesView1.collectionModel}"
  </f:facet>
  <f:facet name="bottom">
  <!--  parameter form goes here -->
  </f:facet>
  <f:facet name="center"/>
  <f:facet name="start"/>
  <f:facet name="end"/>
  <f:facet name="top"/>
</af:panelStretchLayout>
Next step is to identify the layout for second part(parameter form) of the screen. Th challenge here is the uneven distribution of the UI elements across rows. Though panelFormLayout comes close to the requirement, unfortunately this doesn't give the desired out put. Time to look around for a smart component which acts more like wrapper over HTML <table> element. Search ends in Trinidad libraries where we can see our friend - <trh:tableLayout>. Please note that Trinidad components doesn't have any client peer components as we do have for ADF Faces. So you may need to be measured while choosing this guy.

Adding the Trinidad tag library

First step is to add the the required Trinidad tag libraries to your web project's class path. Select the web project, right click and select project properties. Using the Project properties window add the 'Trinidad Components' from the list.

Organizing the content using <trh:tableLayout>

<trh:tableLayout> is supposed to have <trh:rowLayout> for each row and <trh:rowLayout> in turn can take <trh:cellFormat> to hold the UI components. In this example, we may need to have 3 rows. Each <trh:rowLayout> can take different number of <trh:cellFormat> based on number of UI elements to be displayed in a row. Please note that you may need to keep label separate from the <af:inputText> for better result. To achieve this, set the attribute 'simple' as true for inputText component, and add a separate <af:outputLabel> for labeling each inputText field.


The last step in this exercise is to specify the columnSpan and rowSpan properties for <trh:cellFormat>. This decides whether cells can span across more than one column or row. This is an easy task if you have an 'overlay grid' drawn on top of the screen elements as we discussed at the beginning.


Finally, the high level mapping between the UI elements and layout components may look like as shown in the following diagram


You can download the sample workspace from here.
Please try running main.jspx to get a feel of the <trh:tableLayout> component.
[Runs with Oracle JDeveloper 11g R1 PS2 + HR Schema]


Learn More ...

There are a lot more points like this. If  you are curious to learn the internals of the ADF Business Components and ADF Binding Layer,  the following book is for you - Oracle ADF Real World Developer’s Guide.
More details about this book can be found in this post- http://jobinesh.blogspot.in/2012/07/pre-order-your-copy-of-oracle-adf-real.html

Comments

Very good post as usual! :) Although I had some problems in inheriting width of one type of components to the other.
http://adfhowto.blogspot.com/2010/11/adf-ui-layout-components-cannot-see.html
Anonymous said…
Thanks a lot for your tuto it hepls me a lot !

Popular posts from this blog

How to set Bind Variable Values at runtime ?

In this post I'm sharing a couple of approaches for programmatically setting bind variables values at run time. This post is an attempt to explain 'When to use what ?'[ In case if you are familiar with 'Bind Variables' in ADF BC, please refer Section 5.10, Working with Bind Variables in Fusion Developer's Guide ]

1. Set the Bind Variable value using RowSet::setNamedWhereClauseParam(...)

You can use use the setNamedWhereClauseParam(...) method on the ViewObject interface (which extends oracle.jbo.RowSet) to set the value for bind variables. Please note this sets the value on default RowSet. In other words, this doesn't have any effect on the secondary RowSets that you/system generates.
ViewObject vo = am.findViewObject("EmployeesView1"); vo.setNamedWhereClauseParam("bindVarDeptId", new Number(10)); vo.executeQuery();
2. Set the Bind Variable value using ViewObject's VariableValueManager::setVariableValue(...)

VariableValueManager Ma…

Happy New Year 2018 !

We can't go back and change the beginning, but we always can start where we are and change the ending. Believe in yourself and you will be unstoppable!

Wishing you and your family a very happy new year 2018 !!!