Conditional rendering of subclasses within JSF ui:repeat tag
in a way similar to here I am using an abstract class to type the item set list of ui:repeat. Concrete subclasses override the getType() method, that is used to conditionally render the respective subtype with its particular properties:
<!-- AbstractAction Rule#getActions() -->
<ui:repeat value="#{rule.actions}" var="action">
<!-- render when "action" in开发者_运维问答stance of NotificationAction -->
<h:panelGroup rendered="#{action.type == 'notification'}">
... UI for NotificationAction properties
<h:panelGroup rendered="#{action.type == 'callback'}">
...
When run on Glassfish 3 there is an error about properties not being defined on list members of other subclasses (PropertyNotFoundException), which occurs in a branch that is actually switched off by the rendered property. c:forEach/c:choose do not seem appropriate. Any ideas how to make the rendering really conditional and bypass the property checking are highly appreciated!
Thank you. Jaro
after some testing it turned out, that the ui:repeat component itself caused the error. Despite being in the final RenderResponse phase it tries to save the status of its child input components. Here a shortened exception dump:
Caused by: javax.el.PropertyNotFoundException: ... The class FOO does not have a readable property 'BAR'.
at com.sun.faces.facelets.el.TagValueExpression.getValue(TagValueExpression.java:104)
at com.sun.faces.facelets.component.UIRepeat.saveChildState(UIRepeat.java:343)
at com.sun.faces.facelets.component.UIRepeat.setIndex(UIRepeat.java:428)
at com.sun.faces.facelets.component.UIRepeat.process(UIRepeat.java:522)
at com.sun.faces.facelets.component.UIRepeat.encodeChildren(UIRepeat.java:926)
at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1613)
at javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:273)
at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:127)
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
Hereby the rendered condition is ignored and the EL interpreter complains about non-existent properties. There is a simple solution by using the h:dataTable iterator with a single column instead:
<h:dataTable value="#{rule.systemActions}" var="action">
<c:set var="name" value="#{action.class.simpleName.toLowerCase()}" />
<h:column>
<h:panelGroup rendered="#{name == 'notification'}">
<h:outputLabel for="phone">Phone:</h:outputLabel>
<h:inputText value="#{action.phone}" id="phone" />
</h:panelGroup>
<h:panelGroup rendered="#{name == 'reminder'}">
...
</h:panelGroup>
</h:column>
</h:dataTable>
Cheers.
Jaro
精彩评论