Tuesday, October 14, 2008

JSF MyFaces tree2 Practice

I have tried using the MyFaces Tomahawk custom tree2 component in a UI project of mine. I had to show a hierarchy of beans; in addition, each bean had several list properties which also had to be editable and shown as part of one big heterogeneous tree structure.

Here are my observations:
  • not nearly as simple and quick to get going as JSF sets the standard for
  • does not seem to work inside the h:dataTable element!
  • out-of-the-box, client-side node expand/collapse state does not react cleanly to tree modifications
Bean model implementation took a couple of tries to get decent, since node objects must implement the TreeNode interface. The cleanest result was to just roll a usual bean model, implement a TreeNodeBase subclass with a generic Object "data" field and then have a "getTreeRoot" method on the top-level element that would walk the model and build a corresponding tree of nodes. That way, I could have JSF tags get directly at the original model bean via the "data" field with no extra fuss.

The alternative included making model beans directly subclass TreeNodeBase, but that got messy fast.

I don't know if someone implemented that already, but I was aching to have a JSF tree component that would not impose a custom tree node interface model. The cleanest implementation would just take an arbitrary root node bean value and then recursively invoke a special "get child nodes" EL expression on it and its children. For example, assume that you have an "Account" model bean class, and it has a "getChildAccounts" method that returns an array or list. Here is what I'd expect the tag to look like:

<x:myAwesomeTree nodeVar="acct" value="#{blahblah.rootAccount}" children="#{acct.childAccounts}">
... usual JSF tags referencing the acct variable ...

I should mention that I ended up ditching the tree2 tag after all. I just made a special tree-walker method that returns a list of all nodes in my tree structure in traversal order. That list is shown directly as a bunch of divs via t:dataList tag. Then, each node tells how many ancestors it has, which sets the CSS left-margin attribute. Yep, that's right. Cheap and dirty won the day.

In fact, even after that I ran into performance and usability issues... I think that I should have made a Swing-based UI delivered via Java WebStart. For my need - a complex, rarely-accessed administrative interface - it fits the bill best. But oh well, that is a task for another day.

No comments: