In this blog, I will explain how to show or hide the expand icon of an af:tree component depending on available children.

The image on the left shows how a simple af:tree component renders. We see that each of the master nodes (departments) shows an icon that is used to expand the node. The problem is that there is no visible hint if a master node does have children.

The image on the right is what we like to see. Only nodes with children (departments that have employees) show the expand icon. This way, a user directly has a visual hint if a master node has children.

Solution

The solution to the problem is easy. The idea is to check if a node has children and, in this case, to draw over the existing expand icon using the background ink. This will hide the icon, and we get the look of the right image above.

Checking if a node has children can be done using an expression language (EL) term:

#{empty node.children}

This EL uses the node property defined for the tree. It accesses the children of the node. If the returned value is empty, the EL is true. In this case, we render an image over the ‘expand icon’ from the tree using the background ink. Using the rendered property, we can show/hide the default expand icon.

<f:facet name="nodeStamp">
    <af:group id="g1">
        <af:image source='/images/Transparent.png' id="i1"
                  inlineStyle="position:absolute; margin-left:-20px;  margin-top:3px; width:18px; height:15px; background-image:url(afr/alta-v1/tile.png); background-repeat:repeat; background-position:0% 0%; background-size:6px 6px;"
                  rendered="#{empty node.children}"/>
        <af:outputText value="#{node}" id="ot2"/>
    </af:group>
</f:facet>

We use the ‘nodeStamp’ facet to add an image that we only render if there are no children for the node stamped out.  

The image is a transparent png file of 10×10 pixels. The transparent color is needed to later use the current background ink shine through. We could create an image directly using the right background color. The disadvantage is that we have to create the image again whenever we use a different background. Making the image transparent allows us to use the background color or background-image as an inlineStyle.

We provide the width and height needed to paint over the existing ‘expand icon’. We move the image to the left by giving a negative ‘left-margin’. Finally, we set the ‘background-image:url’ to the background of the current skin. For the ‘alta-v1.desktop’ skin, this is ‘afr/alta-v1/title.png’.

If you use another skin, you can use your browser’s developer tools to inspect the page and look for the right values.

Solution for large trees

This solution comes with some costs you have to take into consideration. For the framework to know which of the master nodes have children, it has to look for them for each master node. This isn’t a problem if the number of master nodes is small. It is a problem if you have many master nodes. The queries needed to find out if a node has children will add up some time, making your page slow.

Instead of letting the framework check each parent node for children (using the EL term from above), you can outsource this to the database. The DB is usually better equipped for such tasks. 

You can change the SQL behind the ViewObject to add another attribute returning the number of children. If you name this attribute, e.g. noOfChildren, you can use this in the EL of a node like

#{node.noOfChildren eq 0}

for the rendered attribute of the image. The framework doesn’t have to look for children for each node as the number of children is part of each node.

Sample

You can download the sample I used from GitHub BlogTreeDemo. The sample uses the HR DB schema.

Timo Hahn