I want to set a ui:param depending on a bean value and I thought using c:if was a good idea. So I put in my page the following code:
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:wai="http://www.id.ethz.ch/wai/jsf"
template="/view/listView.xhtml">
<c:if test="#{subscriptionListController.model.listViewName eq 'mySubscriptions'}">
<ui:param name="title" value="#{msg.subscriptionTitleMySubscriptions}"/>
</c:if>
<c:if test="#{subscriptionListController.model.listViewName eq 'paidSubscriptions'}">
<ui:param name="title" value="#{msg.subscriptionTitlePaidSubscriptions}"/>
</c:if>
<c:if test="#{subscriptionListController.model.listViewName eq 'allSubscriptions'}">
<ui:param name="title" value="#{msg.subscriptionTitleAllSubscriptions}"/>
</c:if>
....
but the parameter is not set...
If I let print out the value of #{subscriptionListController.model.listViewName eq 'mySubscriptions'}
I get true in the corresponding case and false in the other two cases.
At the beginning I had only 2 possibilities and solved it with the ternary operator:
<ui:param name="title" value="#{subscriptionListController.model.listViewName eq 'mySubscriptions' ? msg.subscriptionTitleMySubscriptions : msg.subscriptionTitlePaidSubscriptions}"/>
and it worked. But now I have more possibilities...
What am I doing wrong?
As indicated by <ui:composition template>
, this page represents a template client.
Any <ui:param>
outside <ui:define>
applies to the master template (the file which you declared in template
attribute) and is ignored inside the template client itself. If you intend to prepare variables for inside the template client, you should put <ui:param>
inside <ui:define>
.
But there's another thing: the original purpose of <ui:param>
is to pass variables to the file referenced by <ui:composition template>
, <ui:decorate template>
or <ui:include src>
, not to prepare/set variables inside the current facelet context. For the sole functional requirement of preparing/setting variables in the current EL context, you'd better be using JSTL <c:set>
for the job. You can use <ui:param>
for this, but this isn't its original intent and didn't work that way in older MyFaces versions.
Thus, so:
<ui:define>
<c:if test="#{subscriptionListController.model.listViewName eq 'mySubscriptions'}">
<c:set var="title" value="#{msg.subscriptionTitleMySubscriptions}"/>
</c:if>
<c:if test="#{subscriptionListController.model.listViewName eq 'paidSubscriptions'}">
<c:set var="title" value="#{msg.subscriptionTitlePaidSubscriptions}"/>
</c:if>
<c:if test="#{subscriptionListController.model.listViewName eq 'allSubscriptions'}">
<c:set var="title" value="#{msg.subscriptionTitleAllSubscriptions}"/>
</c:if>
...
</ui:define>
Unrelated to the concrete problem, you can optimize this as follows without the need for an unmaintainable <c:if>
group which would only grow with every subscription type:
<ui:define>
<c:set var="subscriptionTitleKey" value="subscriptionTitle.#{subscriptionListController.model.listViewName}">
<c:set var="title" value="#{msg[subscriptionTitleKey]}"/>
...
</ui:define>
with those keys
subscriptionTitle.mySubscriptions = Title for my subscriptions
subscriptionTitle.paidSubscriptions = Title for paid subscriptions
subscriptionTitle.allSubscriptions = Title for all subscriptions
You are using JSTL with Facelets. JSTL are executed during view build time, and not in render phase. Additionally there some issues with processing them in JSF2 libraries - like in older Mojarra versions, where they didn't work on view scoped beans with partial state saving - see https://stackoverflow.com/a/3343681). This is why your EL expression has worked.
The solution is to avoid JSTL - use ui:repeat instead c:forEach and EL expression and conditional rendering instead of c:if.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With