This is achievable with EL 3.0 stream API. My initial attempt was:
<h:panelGroup rendered="#{component.children.stream().filter(c -> c.rendered).count() gt 1}">
<h:outputText value="title" />
<h:panelGroup rendered="#{false}">item1</h:panelGroup>
<h:panelGroup rendered="#{false}">item2</h:panelGroup>
<h:panelGroup rendered="#{false}">item3</h:panelGroup>
</h:panelGroup>
However, that didn't work quite well. It unexpectedly ran into an infinite loop which ultimately ended with an OutOfMemoryError
. It appears that #{component}
EL variable still represents the previous component at the moment the rendered
attribute is consulted. This is a bit of a chicken-egg issue: the #{component}
for current component is only injected if its rendered
attribute evaluates true
.
Given that, I can see two more options: explicitly find the component by ID as below,
<h:panelGroup id="foo" rendered="#{component.findComponent('foo').children.stream().filter(c -> c.rendered).count() gt 1}">
<h:outputText value="title" />
<h:panelGroup rendered="#{false}">item1</h:panelGroup>
<h:panelGroup rendered="#{false}">item2</h:panelGroup>
<h:panelGroup rendered="#{false}">item3</h:panelGroup>
</h:panelGroup>
or let it print some CSS class which in turn does a display:none;
.
<h:panelGroup styleClass="#{component.children.stream().filter(c -> c.rendered).count() gt 1 ? 'show' : 'hide'}">
<h:outputText value="title" />
<h:panelGroup rendered="#{false}">item1</h:panelGroup>
<h:panelGroup rendered="#{false}">item2</h:panelGroup>
<h:panelGroup rendered="#{false}">item3</h:panelGroup>
</h:panelGroup>