Technology: ADF11g
Developed in: JDeveloper 11.1.1.3.0
Browsers tested: Firefox 3.6.13 and Internet explorer 7 (7.0.6002.18005)
Used database schema: HR
Used tables: EMPLOYEES
Summary
Display an table layout in ADF11 is easy, but I’m annoyed by the horizontal scrollbar in the button of the table. A vertical scrollbar I can imagine, I believe it’s more user friendly then the page range that ADF10 had.
Let’s first see what ADF11 creates when dragging and dropping the Employees table from the data control palette. When the browser has a ‘reasonable’ size it looks like this:
Why is the table that small? The screen is so big I would prefer the table being wider so the vertical scrollbar can disappear. When we make the screen (very) small it’s even worse:
Now we have to scrollbars. The scrollbar underneath the Cancel button is just to make the vertical scrollbar of the table visible. But actually this scrollbar (the one underneath the Cancel button) is the one I would like to keep it’s the scrollbar of the complete page content (like word has a scrollbar if you make the screen smaller then a page).
This issues can easily be solved. Just put in the table:
styleClass="AFStretchWidth"
But know I wonder, why such a use gap between the last column and the vertical scrollbar? If we make the screen small it looks like this:
Now we only have one scrollbar, but if we would add items underneath the table wider as the screen a second horizontal scrollbar will be displayed at the bottom of the page (content so above the Marianne Horsch © ADF footer).
So still I’m not really satisfied by how the table looks. Now look at this wide screen:
That looks fine! Scrollbar just after the last column just where I would expect it. But in a small screen??
Also just like I would like it, at most one horizontal scrollbar but not in the table but at the bottom of the page content.
But how did I achieve this? Well I set the width instead of the styleClass. To be precise, I set the width to 1276.
Calculate the width of the table
You may think 1276, how did she come up with that number? Trial and error? And does it really has to be exactly 1276?
First answer the second question:
This picture is width 1280, there is now a gap between the last column and the scrollbar. So yes it needs to be exactly 1276 (for this table).
Then the first question, was it trial and error? No it wasn’t, you can calculate the width of the table. And it is as follows:
- Sum all the widths of the columns
- Add to this the number of columns multiplied by 5
- If the table has a vertical scrollbar then add 16
- Sum of all width of the columns is 1200 (12 columns each with width 100)
- 12 columns multiplied by 5 is 60
- We have a scrollbar so add 16
- Makes total 1200 + 60 + 16 = 1276.
A generic solution
Of course, you don’t want to recalculate the width of the table every time you add or remove a column, or what if columns are rendered based on criteria such as user roles? And display a scrollbar or not is not fixed as well.
Before the solution is described let us first take a look at the example application:
Setup example application
For this blog an example application is created based on the HR schema. The example application contains an employees table with a filter. For this employees table a bounded task flow is created which is started from the menu.
Model layer
Create the following entities:
Entity name | Based on table of HR schema | Customizations made |
---|---|---|
Employee | EMPLOYEES | None |
Create the following view objects:
View object name | Based on entities | Customizations made |
---|---|---|
EmployeesView | Employee | Added 2 bind variables:
(:b_min_salary IS NULL OR (:b_min_salary IS NOT NULL AND Employee.SALARY >= :b_min_salary)) AND (:b_max_salary IS NULL OR (:b_max_salary IS NOT NULL AND Employee.SALARY <= :b_max_salary)) |
Create an application module HrAppModule which exposes the EmployeesView.
Unbounded task flow
The unbounded task flow from where we start with the solution looks like this:
There are no customizations made, the task flow is created by drag and drop.
Bounded task flow
The employees task flow is a bounded task flows.
The next properties are set (for both bounded task flows):
Property | Value |
---|---|
usePageFragments | false |
Share data controls with calling task flow | true |
Table page
The table pages are created by drag and drop from the Data Controls. The table is dropped as ADF Read-only table with Row Selection and Sorting checked, all columns are displayed.
Underneath the table a Cancel button (af:commandButton) is added which ends the task flow.
af:commandButton property | Value |
---|---|
text | Cancel |
id | cancel |
action | cancel |
immediate | true |
Above the table a panelFormLayout is added that contains 2 input text items and a button.
The input text items have the following properties:
Property | First input text | Second input text |
---|---|---|
binding | #{employeeBean.minSalaryFilter} | #{employeeBean.maxSalaryFilter} |
label | Minimum salary | Maximum salary |
id | minSalaryFilter | maxSalaryFilter |
f:validator binding | #{bindings.Salary.validator} | #{bindings.Salary.validator} |
af:convertNumber groupingUsed | false | false |
af:convertNumber pattern | #{bindings.Salary.format} | #{bindings.Salary.format} |
The af:commandButton has the following properties:
Property | Value |
---|---|
text | Filter |
id | filter |
actionListener | #{employeeBean.filter} |
Add to the page definition of the table page inside the bindings tag:
<attributeValues IterBinding="EmployeesViewIterator"
id="Salary">
<AttrNames>
<Item Value="Salary"/>
</AttrNames>
</attributeValues>
partialTriggers="::filter"
Employee bean
In the table page references are made to the employeeBean. This bean class is defined in the employee task flow:
Managed bean property | Value |
---|---|
Name | employeeBean |
Class | nl.hr.demo.view.beans.EmployeeBean |
Scope | Request |
The bean class contains two class variables RichInputText minSalaryFilter and RichInputText maxSalaryFilter and their accessors.
The bean class also contains the actionListener implementation. In this implementation the EmployeesView is retrieved from the application module and the values of minSalaryFilter and maxSalaryFilter are copied to the EmployeesView and the view is queried:
public void filter (ActionEvent actionEvent) {
EmployeesViewImpl view = getService().getEmployeesView();
view.setb_min_salary(getValue(minSalaryFilter));
view.setb_max_salary(getValue(maxSalaryFilter));
view.executeQuery();
}
private Number getMValue(RichInputText item) {
if (item == null || item.getValue() == null) {
return null;
}
return new Number(((BigDecimal) item.getValue()).intValue());
}
private static HrAppModuleImpl getService() {
DCBindingContainer bc = (DCBindingContainer)FacesContext.getCurrentInstance().getApplication().evaluateExpressionGet(FacesContext.getCurrentInstance(), "#{bindings}", BindingContainer.class);
DCDataControl dc = bc.findDataControl("HrAppModuleDataControl");
return (HrAppModuleImpl) dc.getDataProvider();
}
Class name | Package |
---|---|
BigDecimal | java.math |
FacesContext | javax.faces.context |
ActionEvent | javax.faces.event |
DCBindingContainer | oracle.adf.model.binding |
DCDataControl | oracle.adf.model.binding |
RichInputText | oracle.adf.view.rich.component.rich.input |
BindingContainer | oracle.binding |
Number | oracle.jbo.domain |
Fix the table width
Now we’re ready to fix the table width with a generic solution. For this solution we need:
- A bean class that binds the table and calculates the width (in or exclusive scrollbar)
- Set properties in the table to use the bean class
Bean class
Define in the unbounded task flow a new bean:
Managed bean property | Value |
---|---|
Name | tableBean |
Class | nl.hr.demo.view.util.TableBean |
Scope | Request |
The bean class contains a class variables RichTable table and its accessors.
The bean class contains 1 method which returns the width of the table as an int. The width is calculated by:
- Loop over all columns of the table:
- If the column is rendered and visible then add its width to a local integer and add 1 to another local integer that counts the number of columns.
- Add to the width the number of columns multiplied by 5.
- Retrieve the number of rows in the view object that is displayed by the table:
- Get the value property of the table cast it to a CollectionModel and get the estimatedRowCount value.
- If the number of rows is bigger than the number of rows displayed in the table (the autoHeightRows property of the table) then add 16 to the width.
- Return the width.
public int getWidth() {
if (table == null) {
return 600;
}
try {
int width = 0;
int columns = 0;
List
for (int i = 0; i < list.size(); i++) {
UIComponent component = list.get(i);
if (component instanceof RichColumn) {
RichColumn column = (RichColumn) component;
if (column.isRendered() && column.isVisible()) {
width += new Integer(column.getWidth()).intValue();
columns++;
}
}
}
width += (columns * 5);
int nrRows = 0;
if (table.getValue() != null) {
CollectionModel tableData = (CollectionModel) table.getValue();
nrRows = tableData.getEstimatedRowCount();
}
if (nrRows > table.getAutoHeightRows()) {
width += 16;
}
return width;
} catch (Exception e) {
e.printStackTrace();
return 600;
}
}
Class name | Package |
---|---|
List | java.util |
UIComponent | javax.faces.component |
RichColumn | oracle.adf.view.rich.component.rich.data |
RichTable | oracle.adf.view.rich.component.rich.data |
CollectionModel | org.apache.myfaces.trinidad.model |
Table properties
Set the following properties of the employees table:
Property | Value | Description |
---|---|---|
binding | #{tableBean.table} | Binds the table to the RichTable class variable of the TableBean |
width | #{tableBean.width} | The width is set to the result of the getWidth method of the TableBean |
autoHeightRows | 10 | The (maximum) number of rows displayed in the screen |
contentDelivery | immediate | Must be set to immediate otherwise the autoHeightRows property doesn’t work |
Note: Firefox displays one row more than set in the autoHeightRows property . When the autoHeightRows property is set to 10 and there 11 rows in the view object the table bean adds space for a scrollbar but because firefox displays 1 row more the scrollbar space is empty.
Too avoid this a small correction should be made to the TableBean (only tested in IE and Firefox):
Change:
if (nrRows > table.getAutoHeightRows()) {
if (nrRows > (table.getAutoHeightRows() + browserCorrectionRowsDisplayed())) {
public int browserCorrectionRowsDisplayed() {
String browser = (RequestContext.getCurrentInstance()).getAgent().getAgentName();
if (browser != null && browser.equalsIgnoreCase("gecko")) {
return 1;
}
return 0;
}
Geen opmerkingen:
Een reactie posten