Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Setting ui:param conditionally

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?

like image 524
Francesco Avatar asked Dec 04 '13 10:12

Francesco


2 Answers

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
like image 142
BalusC Avatar answered Jan 04 '23 23:01

BalusC


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.

like image 31
Web Devie Avatar answered Jan 05 '23 00:01

Web Devie