copied completely from the following site, author unknown to me
http://www.mediafly.com/Podcasts/Episodes/ADF_Faces_ADF_Faces_Tree_Drilldown_Example
Another lost example: The workspace linked by this blog entry shows how to use a
command link to drill down to detail records shown in a table.
The drilldown functionality - though not shown as a stand alone example - is
documented by Steve Muench in the context of the ADF BC version in the SRDemo
and the ADF Business Components developer guide. In this blog entry I'll give
you two examples - the one provided in the developer guide and one less
declarative but code centric example.
The ADF BC Developer Guide version
The ADF BC Developer Guide version sets the row currency for the data displayed
in the form by clicking on the tree node links. To get to a specific user entry,
you click the location node, expand the department node and then click onto the
user name entry.
Clicking the department node entry shows the first record by default, which
allows you to build an input form with navigation buttons. While this works
nicely, having to click on each and every tree node along the path down to the
user entry may not be considered user friendly.
Firstly, make sure you created iterators for each of the ViewObjects invloved:
LocationsView, DepartmentsView, EmployeesView
This solution is implemented through the setCurrentRowWithKey operation, which
is exposed as an operation on the LocationView, DepartmentsView and
EmployeesView. Open the pageDef file in the Structure Window and select the
bindings node.
From the context menu select the option to create a new Action. Select the
LocationView instance that represents the top view in the tree structure. Choose
the setCurrentRowWithKey option from the drop down.
Its important to set the rowKey value to #{node.rowKeyStr} so that the selected
node's key value is passed to the operation. the "node" string is a variable
name contained in the page when building the tree and you have to type it into
the value field (the ExpressionLanguage builder doesn't see this variable name)
After building the action, make sure you give it a good and readable name by
changing the default name in the property inspector for the action.
Next step is to create a binding of the tree component to a managed bean. The
binding is used later to detect the depth of the tree, which is important for
the command link to access the right setCurrentRowsWithKey action.
The tree nodes are defined by three command link components, according to the
expected tree depth of location -- department -- employees.
Each of the command links is displayed or hidden based on one of the following
conditions added to the "rendered" property
#{TreeManagedBean.treeHandler.depth==0}
#{TreeManagedBean.treeHandler.depth==1}
#{TreeManagedBean.treeHandler.depth==2}
This means that e.g. the command link with the ActionListener set to execute the
setCurrentRowWithKey operation for the employees view, is shown or hidden by #{TreeManagedBean.treeHandler.depth==2}
Last, but not least, each of the command links needs to be linked to one of the
setCurrentRowWithKey actions.
This way, when the node is clicked on, the underlying ViewObject row currency is
set to the selected row. Also note that the command links don't use PPR (partial
submit = false).
PLAIN TEXT
XML:
actionListener="#{bindings.setCurrentLocationRowWithKey.execute}"
rendered="#{TreeManagedBean.treeHandler.depth==0}"/>
id="nodeAction2"
rendered="#{TreeManagedBean.treeHandler.depth==1}"
actionListener="#{bindings.setCurrentDepartmentsRowWithKey.execute}"/>
id="nodeAction3"
rendered="#{TreeManagedBean.treeHandler.depth==2}"
actionListener="#{bindings.setCurrentEmployeesRowWithKey.execute}"/>
Note that for the JSF form to show the selected employee, the input form must be
based on the EmployeeView instance contained in the LocationView tree.
Custom example
The custom example solves the usability concern of the version documented in the
ADF BC developer guide so tha only the leaf nodes are shown as hyperlinks.
Later, in the implementation, you will see that the risk with this version lies
in how the node tree key is parsed.
As for the documented ADF BC tree drill down example, you need to create
iterator bindings for all the ViewObject instances that are involved. Also you
need to create a binding from the tree component to a managed bean.
Instead of using three command links that are used in the previouse example, you
use one output text component and one command link. The command link is set to
partial submit and also has an id assigned to it so it triggers the refresh of
the JSF input form.
Note that the output text component is rendered for all tree depth that are
below 2, whcih means for locations and employees.
The ActionListener property on the commandLink component is set to #{TreeManagedBean.nodeSelected},
which is a managed bean method.
PLAIN TEXT
CODE:
public void nodeSelected(ActionEvent actionEvent){
String rowKeyStr = getTreeHandler().getRowKey().toString();
String[] path = rowKeyStr.split(", ");
if (getTreeHandler().getDepth()==2){
int locIndx = new Integer(path[0].substring(1)).intValue();
int depIndx = new Integer(path[1].substring(0)).intValue();
int empIndx = new Integer(path[2].substring(0,path[2].indexOf("]"))).intValue();
// System.out.println(locIndx);
// System.out.println(depIndx);
// System.out.println(empIndx);
FacesContext fctx = FacesContext.getCurrentInstance();
ValueBinding vb = fctx.getApplication().createValueBinding("#{bindings.LocationsView1Iterator}");
DCIteratorBinding dciterLocationsView = (DCIteratorBinding)vb.getValue(fctx);
dciterLocationsView.getRowSetIterator().setCurrentRow(dciterLocationsView.getRowAtRangeIndex(locIndx));
vb = fctx.getApplication().createValueBinding("#{bindings.DepartmentsView3Iterator}");
DCIteratorBinding dciterDepartmentsView = (DCIteratorBinding)vb.getValue(fctx);
dciterDepartmentsView.getRowSetIterator().setCurrentRow(dciterDepartmentsView.getRowAtRangeIndex(depIndx));
vb = fctx.getApplication().createValueBinding("#{bindings.EmployeesView4Iterator}");
DCIteratorBinding dciterEmployeesView = (DCIteratorBinding)vb.getValue(fctx);
int empRangeSize = dciterEmployeesView.getRangeSize();
int empRangeIndx = 0;
int empRowIndx = 0;
if (empIndx + 1> empRangeSize){
empRangeIndx = empIndx/ empRangeSize;
empRowIndx = empIndx % empRangeSize;
dciterEmployeesView.getRowSetIterator().setRangeStart(dciterEmployeesView.getRangeSize()*empRangeIndx);
empIndx = empRowIndx;
}
dciterEmployeesView.getRowSetIterator().setCurrentRow(dciterEmployeesView.getRowAtRangeIndex(empIndx));
//additional partial target needed to be set
AdfFacesContext.getCurrentInstance().addPartialTarget(formHandler);
}
}
Because the user clicks on an employee enttry only, the manage bean method
parses the row key, which comes in the format of [location index, department
index, employee index]
For example --- [0, 1, 13] identifies the 14th employee node of the second
departments node under the first location
Knowing about the tree structure, this information is then used to determine the
current row and setting it (similar to what clicking each of the commanLink does
in the first example)
PLAIN TEXT
CODE:
FacesContext fctx = FacesContext.getCurrentInstance();
ValueBinding vb = fctx.getApplication().createValueBinding("#{bindings.LocationsView1Iterator}");
DCIteratorBinding dciterLocationsView = (DCIteratorBinding)vb.getValue(fctx);
dciterLocationsView.getRowSetIterator().setCurrentRow(dciterLocationsView.getRowAtRangeIndex(locIndx));
The code line above sets the currentRow for the locations iterator based on the
location tree node that the selected employee is a member of.
If you access ViewObjects that use page ranges, which is recommended to not
always query the whole data, you must be aware of the possibility that a
selected node - eg. employee node in this example - is not in the first
(default) range. The range by default is set to 10 records. This setting is
defined on the iterator binding properties.
To access the correct row, you need to get the range size out of the employee
index. E.g. employee 23 means that it is the 4th record (counting starts by 0)
in the 2nd range (also counting from zero)
PLAIN TEXT
CODE:
int empRangeSize = dciterEmployeesView.getRangeSize();
int empRangeIndx = 0;
int empRowIndx = 0;
if (empIndx + 1> empRangeSize){
empRangeIndx = empIndx/ empRangeSize;
empRowIndx = empIndx % empRangeSize;
dciterEmployeesView.getRowSetIterator().setRangeStart(dciterEmployeesView.getRangeSize()*empRangeIndx);
empIndx = empRowIndx;
}
Setting the range start ensures that the employee index (3 if the index number
was 23) can be looked up
To run the application, you need to
Get the workspace from here
Copy adf-faces-impl.jar from jdeveloper_10131_3984\jlib to AdfFacesTreeSample\ViewController\public_html\WEB-INF\lib
and AdfFacesTreeSample\ViewController2\public_html\WEB-INF\lib
Copy jsf-impl.jar from jdeveloper_10131_3984\jsf-ri to AdfFacesTreeSample\ViewController\public_html\WEB-INF\lib
and AdfFacesTreeSample\ViewController2\public_html\WEB-INF\lib
Create a named database connection hrconn in Jdeveloper
Run TreeNode.jsp or TreeNode2.jsp