Thursday, August 27, 2009

ADF Faces (Trinity): af:forEach and af:table...think twice

Rule of thumb: be careful of using af:forEach in af:table rows to generate the options of a select list. Much safer to use getter to get a list and plug into value of f:selectItems (plural), than to use f:selectItem (singular) and use af:forEach to iterate over. af:iterator might work instead of af:forEach, too, but I am not sure.

Also mixed in with this was using forEach's varStatus property...something I have had bad luck with in the past.

Basically what was happening, was this forEach was not even on a part of the screen that was getting rendered, but it was causing components to render multiple times and get all mixed up. Pretty hard to track down.

So in this particular case I would get this doubling when I used the following inside of an af:selectOneChoice...

<af:forEach begin="1"
end="#{bindings.SomeIterator.estimatedRowCount}"
var="priorityRow"
varStatus="priorityLoop">
<f:selectItem itemLabel="#{priorityLoop.index}"
itemValue="#{priorityLoop.index}"/>
</af:forEach>

...instead of using someting like the following...
<f:selectItems
value="#{SomeBackingBean.someHashMapProperty[bindings.SomeIterator.estimatedRowCount]}"/>

The use-case for this problem was a bit odd, but nothing too bad...

Sunday, August 23, 2009

af:menuBar selected style

If you want to use af:commandMenuItem inside an af:menuBar, with the af:commandMenuItem's selected property set to a particular value (true, false, EL), that is great. Just remember you cannot embed your af:commandMenuItem inside some other component and have this selected work...even if that other component is embedded inside an af:menuBar component. The CSS that is generated by the skin selector for the af:menuBar for this purpose is picky about how it wants to see things: td. a

Wednesday, August 19, 2009

speaking at NoVAJUG

If you live/work in Virginia, I will be be giving a preliminary viewing of my Oracle Open World presentation on JSF Custom Component basics.

Here is more info on the matter: http://novajug.wordpress.com/2009/08/19/sept-9-lets-make-some-jsf-custom-components-by-michael-a-fons/

Also here is the NoVAJUG website: http://novajug.org/

Tuesday, August 18, 2009

view links internal to sql statement

There is an esoteric aspect of links that I had not really experimented with until yesterday.

First know that it is possible to write a query/view object, that contains a bind variable in the query which is not defined in the list of bind variables in the view object itself.

Why would you want to do this?

What if you wanted (for speed reasons) to put a bind variable referencing a parent query column in a subquery of a query in the child view object?

Well, if you create a view link between the parent and child queries, ADF will automatically create a bind variable on behalf of the view-link with the name "Bind_. So if the parent was DeptView, and the child EmpView, and their connecting view link was DeptView.DeptNo = EmpView.DeptNo, then at run time this view link would create :Bind_DeptNo referenceable in the child query. So you could put this in a sub-query.

At the moment this still leaves the sometimes problem that you may have to have a connecting DeptNo in the child query select clause, but that is only a problem in some cases. This bit of flexibility can be good enough in many cases.

Also this may be a case where the problem is that I am not sure just how much more flexibility ADF/BC will allow. It is quite possible that you could connect these two queries based on bogus columns like select 1 bogus_columnn, ... from ... in both the parent and child, and then change the where clause in the view link to join on :Bind_DeptNo. Maybe it is even more flexible than that; I just am not sure at this time.

Tuesday, August 11, 2009

af:treeTable: getting at a clicked node

Hi.

I was working with an af:treeTable and its accompanying tree binding. I wanted to click a node to open it (if that node had sub nodes) and then automatically do something with the data in that node. I did not want to have to click on a link in the tree to identify the node.

Here is what I came up with:

public void onDisclosure(DisclosureEvent disclosureEvent) {
CoreTreeTable cmt = (CoreTreeTable)disclosureEvent.getSource();
PathSet ps = cmt.getTreeState();
Set ks = ps.getKeySet();
//ks.clear();
// The key-set is the set of addresses of keys that are open.
// Clearing it closes all that are open.

List rwKey = (List)cmt.getRowKey();
// The row-key is the address of the row that was just disclosed/clicked.
// It is a list of Strings, which contain 0-based numbers.
int depth = 0;
for (Object o1 : rwKey) {
ArrayList pathToAdd = new ArrayList();
for (int i = 0; i < depth + 1; i++) {
pathToAdd.add(rwKey.get(i));
}
//ks.add((Object)pathToAdd);
depth++;
}
// This for loop just added the address of the node clicked,
// to the set of "open" nodes. Along the way it also enters
// all the parent node addresses as well, creating a new
// array list to store the address for each ancestor as well as
// the node clicked.

// I want to get the node that was clicked. I should be able to
// use the row-key to traverse the tree model to get the node I want.
TreeModel lTreeModel = (TreeModel)cmt.getValue();
Object lRowData = null;
for (Object lRowKeyIndexObject : rwKey) {
// Can I assume I start out with the tree model looking at root
// node?
String lRowKeyIndexString = (String)lRowKeyIndexObject;
int lIndex = Integer.parseInt(lRowKeyIndexString);
if (lTreeModel.isRowAvailable(lIndex)) {
lRowData = lTreeModel.getRowData(lIndex);// JUCtrlHierNodeBinding
lTreeModel.setRowIndex(lIndex);
}
if (lTreeModel.isContainer()) {
lTreeModel.enterContainer();
}
}
// When the loop is over the tree model should be
// set to the level and row that was clicked.
// Also lRowData should be the row we care about...the
// clicked row.

// We do not have to reset. I think each request the tree model
// resets. Traversing the tree model does not affect the way
// the tree table renders or looks.

JUCtrlHierNodeBinding lNodeBinding = (JUCtrlHierNodeBinding)lRowData;
String lNodeContents = (String)lNodeBinding.getAttribute(1);
// Display the found node.
this.setLSelectedNodeString(lNodeContents);

// Next experiment. Create binding in query
// and a field that allows you to set this binding.
// See if when you open a node if it affects any others nodes
// or not.
}