Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Faking Recursion in JSF

I'm trying to display a tree in JSF without hard-coding the depth of the tree I want to display. Maybe for one configuration I only want to show the leaves, maybe for another I want to show the leaves grouped by the nodes one level above them, etc. So for one configuration, it could be:

  • Question 1
  • Question 2
  • Question 3
  • Question 4

While for another configuration, the same underlying data structure could produce:

  • Category 1:
    • Question 1
    • Question 2

  • Category 2:
    • Question 3

  • Category 3:
    • Question 4

With a hypothetical third configuration grouping the categories by super-categories, etc.

I tried making a composite component that called itself recursively if the node had more children. I did this via <ui:fragment rendered="#{node.hasChildren}"> and -- surprise! -- this resulted in an infinite loop and a stack overflow.

The project already has PrimeFaces installed, so I'm looking at PrimeFaces Tree and TreeNode. But that doesn't quite feel right; I don't want the tree nodes to be expandable in the user interface. I want everything to be fully expanded. I haven't gone too deeply down this rabbit hole so I suspect there may be a way to achieve this with Tree, but it feels like I'm going against the grain of what it's built to do.

What's a good approach this problem?


Edit: I'm trying to use <tree> and <treeNode>, but it's not working. My code looks like this:
<p:tree value="#{cc.attrs.classification}" var="child">
    <p:treeNode>
        <ui:fragment rendered="#{child.childCount > 0}">
            [do node stuff]
        </ui:fragment>
        <ui:fragment rendered="#{child.childCount == 0}">
            [do leaf stuff]
        </ui:fragment>
    </p:treeNode>
</p:tree>

... where classification implements the TreeNode interface. This results in errors to the console complaining that child is of type String and therefore cannot do any of the interesting things I'm asking of it. What am I doing wrong?

like image 673
BlairHippo Avatar asked Dec 01 '25 14:12

BlairHippo


1 Answers

I tried making a composite component that called itself recursively if the node had more children. I did this via and -- surprise! -- this resulted in an infinite loop and a stack overflow.

It failed because rendered attribute isn't evaluated during building the JSF component tree, but only during generating the HTML output. You basically need JSTL <c:if> instead of <some:component rendered>. It runs during building the JSF component tree, so you don't end up in infinitely including the composite itself.


The project already has PrimeFaces installed, so I'm looking at PrimeFaces Tree and TreeNode. But that doesn't quite feel right; I don't want the tree nodes to be expandable in the user interface. I want everything to be fully expanded.

The JSF utility library OmniFaces has exactly the component you're looking for, the <o:tree>. That component doesn't generate any HTML markup by itself, so you've all the freedom to declare the HTML/JSF markup the way you want, also for specific depth levels.

Here's the showcase example. Note the links at the bottom of the page, they point to the source code which may be helpful/interesting as learning exercise. It isn't exactly trivial as you perhaps initially thought while developing the composite (which is after all not exactly the right tool for the job).

As to distinguishing leaf nodes, the <o:tree> offers this possibility as follows:

<o:tree value="#{bean.tree}" var="item" varNode="node">
    <o:treeNode>
        <o:treeNodeItem>
            <ui:fragment rendered="#{not node.leaf}">
                ...
            </ui:fragment>
            <ui:fragment rendered="#{node.leaf}">
                ...
            </ui:fragment>
            <o:treeInsertChildren />
        </o:treeNodeItem>
    </o:treeNode>
</o:tree>
like image 130
BalusC Avatar answered Dec 04 '25 04:12

BalusC



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!