Wednesday, December 12, 2007

All about ADF tables


How do i make a ADF TreeTable ??
Saying it in very simple terms ... (i) first make POJOs ... using parent POJO and child POJO make a tree like hierarchy (ii) then using the ADF model classes convert them into ADF treeTable model !


Step one sounds easy .. can i have more details on step two ?
In ADF we have the following hierarchy...

java.lang.Object
   javax.faces.model.DataModel
      oracle.adf.view.faces.model.CollectionModel
         oracle.adf.view.faces.model.TreeModel
            oracle.adf.view.faces.model.ChildPropertyTreeModel

javax.faces.model.DataModel
has default constructor
inherits directly from java.lang.Object
The data collection underlying a DataModel instance is modeled as a collection of row objects that can be accessed by a zero-relative cursor (row index). The APIs provide mechanisms to position to a specified zero-relative row index, and to retrieve an object that represents the data that corresponds to the current row index.
DataModel is an abstraction around arbitrary data binding technologies that can be used to adapt a variety of data sources for use by JavaServer Faces components that support per-row processing for their child components
has a property rowIndex that starts from 0 ... up to max_no_of_child
has other methods like getRowData() getRowCount() .. setWrappedData() and getWrappedData() .. they set the object representing the data collection wrapped by this DataModel


oracle.adf.view.faces.model.CollectionModel
implements no RowKeyIndex
has default ctor
The data model that is used by ADF Table components. This extends the faces DataModel class and adds on support for rowKeys and sorting.


*** oracle.adf.view.faces.model.TreeModel ***
It just has a default constructor ...

rows in a treeModel may contain other rows...
to figure out if current row is a container use method isContainer()
If a row is a container, use the enterContainer() method to access its child rows. Once the enterContainer() method is called all the CollectionModel API's methods (like DataModel.getRowCount()) operate on the child collection. To return back to the parent row, use the exitContainer() method.

|-Root1 (rowKey="r1", rowIndex=0)
| |-Folder1 (rowKey="r1f1", rowIndex=0)
| | |-Node1 (rowKey="r1f1n1", rowIndex=0)
| | |-Node2 (rowKey="r1f1n2", rowIndex=1)
| | |-Node3 (rowKey="r1f1n3", rowIndex=2)
| |
| |-Folder2 (rowKey="r1f2", rowIndex=1)
| |-Node4 (rowKey="r1f2n1", rowIndex=0)
|
|-Root2 (rowKey="r2", rowIndex=1)
|-Root3 (rowKey="r3", rowIndex=2)
|-Root4 (rowKey="r4", rowIndex=3)

so each row has a setRowKey() and setRowIndex() ... rowKey is inherited from CollectionModel and rowIndex from DataModel... the rowKey is unique accross the whole table ... rowIndex is relative to its parent ...
use setRowKey(null) to reach the root ...

To access Node4 use:

setRowIndex(0); // isContainer()==true
enterContainer(); // enter Root1, getRowCount()==2
setRowIndex(1); // isContainer()==true
enterContainer(); // enter Folder2, getRowCount()==1
setRowIndex(0); // isContainer()==false
getRowData(); // To access a particular row in the list, first make that row current, and then call the getRowData() method on the Table

Or, more simply:
setRowKey("r1f2n1");
getRowData();

*** oracle.adf.view.faces.model.ChildPropertyTreeModel ***
It extends TreeModel

Creates a TreeModel from a List of beans. To use this class you must have a tree of beans (or Maps). The structure of your tree must be a List (or array) of root beans, and each bean must have a getter method (or Map property) that returns the children List. All elements of your tree must be the same type.




Tree VS TreeModel
The Tree component displays a multi-root hierarchy in a simple UI... the TreeTabel displays a single-root hierarchy

You may find the oracle.adf.view.faces.model.ChildPropertyTreeModel class useful when constructing a TreeModel

*** the ***
The "nodeStamp" facet of the Tree is used to display the data for each element in the tree. The Tree does not create components per element; instead, the "nodeStamp" is repeatedly rendered (stamped) once per element. Because of this stamping behavior, only certain types of components are supported as children inside a Tree. Supported components include all components with no behavior and most components that implement the EditableValueHolder or ActionSource interfaces.
The Tree renders expand/collapse icons that the user can click on to expand or collapse a subtree. When these icons are clicked, the Tree generates a DisclosureEvent

The immediate children of a Table component must all be < af:column > components.
Use the "header" facet on a Column to create the column header.
The child components of each Column display the data for each row in that column.... that means it may be a textbox , a label , a textArea etc ...
Column does not create child components per row; instead, each child is repeatedly rendered (stamped) once per row... that means if there are 10 rows then the column elemnt will not create 10 children insteand 10 times rows will be created and each time one element for the column is created

Because of this stamping behavior, some components many not work inside the table. Anything that is just pure output, with no behavior, will work without problems, as will components that don't "mutate" even as they deliver events

one can have column groups ...

Columns can be rendered as row headers by setting the "rowHeader" attribute on < column > to be true. Row header columns must be the first columns in a table.

Range Navigation
When the list being displayed by a Table is huge, you can enable the Table to break up the list into ranges and display a single range at a time. Range controls are provided on the Table to let the user scroll to the next range, or to go back to the previous range.
thi smay also generate RangeChangeEvent

Displaying Details
You can configure the Table to display or hide additional details of a particular row in response to a user gesture. When the details feature is enabled, a new column containing a toggle (per row) will render in the Table. When a toggle is activated, the details for that row are displayed. When a toggle is deactivated, the details for the row are hidden. The user can also display or hide the details for all rows at the same time (the controls for this feature are enabled by setting the "allDetailsEnabled" property to true.)

To enable the details feature set the "detailStamp" facet on the Table. Place the components that are used to show the details (of a row), inside this facet. In the following example, the Person's age is displayed in the details section:







Usually, the default behavior of the Table (with respect to displaying and hiding details) is sufficient. In some cases, however, it might be desirable to programmatically display or hide the details for a particular row. This can be done via the RowKeySet object obtained from the Table by calling the getDisclosureState() method. First, make the relevant row current by calling setRowIndex(...) or setRowKey(...) on the Table, and then call add() or remove() on the RowKeySet object. Adding the row to the set displays the details of the row. Removing the row hides them.



*** ***
The ADF Table component uses a model to access the data in the underlying list. The specific model class is oracle.adf.view.faces.model.CollectionModel . You may also use other model instances, e.g., java.util.List , array, and javax.faces.model.DataModel . The Table will automatically convert the instance into a CollectionModel ...??? not sure how will that happen as there is only one constructor for the CollectionModel and thats the default constructor ???



*** the ***
single-root hierarchy
TreeTable's children must be ADF Column components
the tree table has a "nodeStamp" and a "pathStamp" facet ... Like the Tree, the TreeTable has a "nodeStamp" facet which renders the "Object Name" Column. The TreeTable has a "pathStamp" facet for rendering the focus path.


*** obvious ***
ifmy af:table is inside af:panelcollection .. first panelcollection is made then the table

No comments: