I'm currently fighting a little bit with JSF. I want to display a list of items. Each item can be displayed with 2 facelets (one if the item is editable and one otherwise).
Code snippet:
<div>
<c:forEach items="#{bean.itemList}" var="item">
<c:choose>
<c:when test="#{bean.isEditable(item.id)}">
<ui:include src="#{item.editableFaceletPath}>
<ui:param name="item" value="#{item}" />
</ui:include>
</c:when>
<c:otherwise>
<ui:include src="#{item.normalFaceletPath}>
<ui:param name="item" value="#{item}" />
</ui:include>
</c:otherwise>
</c:choose>
</c:forEach>
</div>
This works fine as long as I don't set an item to editable. However if I have 3 items: item1, item2 and item3, and I set item1 to editable, I'll get item2, item2, item3 displayed.
I understand why it doesn't work but I have absolutely no idea how I could implement it otherwise. Has anyone an idea how?
See this link for an explanation about common mistakes regarding the evaluation in different lifecycle phases of JSF.
The problem is that your JSTL tags will only be evaluated once, when the view is being built. If you change the item to editable, it won't have an effect anymore on the component tree which was built already before.
The solution is to replace the <c:choose><c:when><c:otherwise>
with two <ui:fragment>
s with rendered="#{bean.isEditable(item.id)}"
and rendered="#{not bean.isEditable(item.id)}"
.
That way you will have BOTH branches of the component tree in your view, but at render time only one of them will be evaluated and displayed because of the rendered
attribute.
But this whole construct will only work as long as you do not change the list of items. Because adding or removing items will not effect the <c:forEach>
anymore. In that case you would have to do it completely without <ui:include>
and go with <ui:repeat>
and a combination of <ui:fragment rendered="#{...}">
.