I am using jsf primefaces. I want to display an image depending on the value of a specific outputext. If the text value is 'Alarm *' then a div will appear whith a spesific image. If the value is 'Alarm **' then a div with an other image will appear, etc. I tried the code below but it does not work for me.
<h:outputText id="alarmCriticalityValue" value="#{msg[summary.criticality.key]}" />
<c:if test="#{alarmCriticalityValue=='Alarm *'}">
<div class="alarm1"></div>
</c:if>
How should i implement this idea?
You need to use binding attribute to put the UIComponent instance in the EL scope. The id attribute doesn't do that, on contrary to what you expected.
<h:outputText binding="#{alarmCriticality}" ... />
And then you need to use UIOutput#getValue() to obtain its value attribute.
<c:if test="#{alarmCriticality.value == 'Alarm *'}">
That said, you'd better use rendered attribute here, particularly if #{summary} represents the currently iterated item of a JSF iterating component like <ui:repeat> or <h:dataTable>.
<h:panelGroup layout="block" styleClass="alarm1"
rendered="#{alarmCriticality.value == 'Alarm *'}" />
See also:
How does the 'binding' attribute work in JSF? When and how should it be used?
How to conditionally render plain HTML elements like <div>s?
JSTL in JSF2 Facelets... makes sense?
Unrelated to the concrete problem. It's strange to see the conditional rendering depend on localized text. What if you change the locale and/or the localized text? This is very brittle. You'd better check the bundle key instead.
<h:outputText value="#{msg[summary.criticality.key]}" />
<h:panelGroup layout="block" styleClass="alarm1"
rendered="#{summary.criticality.key == 'some.alarm.key'}" />
This way you also don't need to bind the output text anymore.
Try
<c:if test="#{msg[summary.criticality.key].equals('Alarm *')}">
Or add a binding to the h:outputText and check against that.
Try this
<h:outputText id="alarmCriticalityValue" value="#{msg[summary.criticality.key]}" />
<h:panelGroup layout="block" styleClass="alarm1" rendered="#{alarmCriticality.value eq 'Alarm *'}" />
Related
I want to use a selectOneMenu to have a user choose a value. In some cases I want to disable one of the values shown in the menu. I tried using render on both the selectItems as well as selectOneMenu as well as added a ui:fragment around the Menu but I always get all the values from both lists shown. Any ideas how to prevent that?
Here my current last try that again resulted in twice the list and the item in question once enabled and once disabled in it:
<ui:fragment rendered="#{cc.attrs.showP==true}">
<h:selectOneMenu id="type" binding="#{cc.type}">
<f:selectItems value="#{typeDAO.findAll()}"/>
</h:selectOneMenu>
</ui:fragment>
<ui:fragment rendered="#{cc.attrs.showP==false}">
<h:selectOneMenu id="type" binding="#{cc.type}">
<f:selectItems value="#{typeDAO.findAll()}" var="item" itemDisabled="#{item=='P'}"/>
</h:selectOneMenu>
</ui:fragment>
Your concrete problem is caused because you're binding physically multiple components to the same variable.
<h:selectOneMenu ... binding="#{cc.type}" />
<h:selectOneMenu ... binding="#{cc.type}" />
If the getter behind binding returns non-null, then JSF will use it instead of creating a new one. Basically, the second tag will reuse the component created in the first tag and set/add all attributes/items to it.
Your particular case can be solved in at least two ways:
Use JSTL to build the JSF component tree conditionally instead of using JSF to render the HTML output conditionally. You shouldn't have physically multiple components in the JSF component tree sharing the same binding let alone the same id.
<c:if test="#{cc.attrs.showP}">
<h:selectOneMenu id="type" binding="#{cc.type}">
...
</h:selectOneMenu>
</c:if>
<c:if test="#{not cc.attrs.showP}">
<h:selectOneMenu id="type" binding="#{cc.type}">
...
</h:selectOneMenu>
</c:if>
Make your code DRY. I.e. get rid of all code duplication.
<h:selectOneMenu id="type" binding="#{cc.type}">
<f:selectItems value="#{typeDAO.findAll()}" var="item" itemDisabled="#{not cc.attrs.showP and item eq 'P'}" />
</h:selectOneMenu>
See also:
How does the 'binding' attribute work in JSF? When and how should it be used?
JSTL in JSF2 Facelets... makes sense?
Guess I found it - bit weird to answer my question though. I think it's because the possible values of the menu are created before the rendered attributes are evaluated and since I did bind both menus to the same variable/id I got all items of the two menus. Thus I now used different names and then in my composite component have some logic that checks which one is used and continues to use the right value. Works :-)
Bit weird to me is this thing that as a developer u have to know when the attribute list is built in comparison to when the rendering happens. I recently had a similar issue with foreach and repeat. Is there any way to know these things as part of some overarching concept that I can remember or is that really case by case?
Thanks guys!
I am trying to conditionally build a custom list using <ui:repeat>. On every occurrence of -1 as item-value in list, I need to add a line break.
I tried to use <c:if> inside <ui:repeat> for that, but it does not seem to work. It always evaluates false.
<ul>
<ui:repeat value="#{topics.list}" var="topicId" >
<li>#{topicId}</li>
<c:if test="#{topicId eq -1}"> <br/> </c:if>
</ui:repeat>
</ul>
Is this possible?
Not with JSTL tags, no. They run during view build time, not during view render time. You can visualize it as follows: when JSF builds the view, JSTL tags run from top to bottom first and the result is a pure JSF component tree. Then when JSF renders the view, JSF components run from top to bottom and the result is a bunch of HTML. So, JSTL and JSF don't run in sync as you'd expect from the coding. At the moment your <c:if> JSTL tag tag runs, the #{topicId} variable which is set by <ui:repeat> JSF component isn't available in the scope.
Instead of using <c:if>, you need to specify the condition in the rendered attribute of the JSF component of interest. As you've actually none, you could wrap it in a <ui:fragment>.
<ul>
<ui:repeat value="#{topics.list}" var="topicId" >
<li>#{topicId}</li>
<ui:fragment rendered="#{topicId eq -1}"><br/></ui:fragment>
</ui:repeat>
</ul>
Alternatives are <h:panelGroup>
<h:panelGroup rendered="#{topicId eq -1}"><br/></h:panelGroup>
or in your specific case <h:outputText escape="false">
<h:outputText value="<br/>" escape="false" rendered="#{topicId eq -1}" />
as both also emits nothing else to the HTML output when no client side attributes are specified.
See also:
JSTL in JSF2 Facelets... makes sense?
Unrelated to the concrete problem, that's the wrong place for a <br/>. It would be ignored by any webbrowser respecting the HTML specification. Don't you mean it to be inside the <li>? Or better, give it a class and let CSS give it a margin-bottom.
I'm using an <h:outputLink> as follows.
<c:set var="cid" value="1"/>
<c:set var="sid" value="2"/>
<h:outputLink value="Test.jsf">
<h:outputText value="Link"/>
<f:param name="cid" value="#{cid}"/>
<f:param name="sid" value="#{sid}"/>
</h:outputLink>
This is just an example. Both of the query-string parameters are dynamic. So, <c:set> used here is just for the sake of demonstration.
At any time, either one, both or none of the parameters may be present. In case, if only one or none of them is present then, parameter/s are unnecessarily appended to the URL which should not happen. Preventing unnecessary query-string parameters from being appended to the URL requires a conditional rendering of <f:param>.
JSTL <c:if> like the following
<c:if test="${not empty cid}">
<f:param name="cid" value="#{cid}"/>
</c:if>
did not work.
How can it be made possible to conditionally render <f:param> inside <h:outputLink>?
The <f:param> has a disable (not disabled!) attribute for the purpose.
<f:param name="cid" value="#{cid}" disable="#{empty cid}" />
<f:param name="sid" value="#{sid}" disable="#{empty sid}" />
Note that this has a bug in Mojarra versions older than 2.1.15, because they typo'ed the actual UIParameter property to be disble instead of disable. See also issue 2312.
As to the <c:if> approach, that would only work if the #{cid} and #{sid} is available during view build time. In other words, it would fail if they are only available during view render time, e.g. when they depend on var of a repeater component. See also JSTL in JSF2 Facelets... makes sense?
See also:
f:param tag attribute 'disable' is not work
Don't you like this kind of a solution?
<f:param name="#{cid == null ? '' : 'cid'}" value="#{cid}"/>
<f:param name="#{sid == null ? '' : 'sid'}" value="#{sid}"/>
I am trying to conditionally build a custom list using <ui:repeat>. On every occurrence of -1 as item-value in list, I need to add a line break.
I tried to use <c:if> inside <ui:repeat> for that, but it does not seem to work. It always evaluates false.
<ul>
<ui:repeat value="#{topics.list}" var="topicId" >
<li>#{topicId}</li>
<c:if test="#{topicId eq -1}"> <br/> </c:if>
</ui:repeat>
</ul>
Is this possible?
Not with JSTL tags, no. They run during view build time, not during view render time. You can visualize it as follows: when JSF builds the view, JSTL tags run from top to bottom first and the result is a pure JSF component tree. Then when JSF renders the view, JSF components run from top to bottom and the result is a bunch of HTML. So, JSTL and JSF don't run in sync as you'd expect from the coding. At the moment your <c:if> JSTL tag tag runs, the #{topicId} variable which is set by <ui:repeat> JSF component isn't available in the scope.
Instead of using <c:if>, you need to specify the condition in the rendered attribute of the JSF component of interest. As you've actually none, you could wrap it in a <ui:fragment>.
<ul>
<ui:repeat value="#{topics.list}" var="topicId" >
<li>#{topicId}</li>
<ui:fragment rendered="#{topicId eq -1}"><br/></ui:fragment>
</ui:repeat>
</ul>
Alternatives are <h:panelGroup>
<h:panelGroup rendered="#{topicId eq -1}"><br/></h:panelGroup>
or in your specific case <h:outputText escape="false">
<h:outputText value="<br/>" escape="false" rendered="#{topicId eq -1}" />
as both also emits nothing else to the HTML output when no client side attributes are specified.
See also:
JSTL in JSF2 Facelets... makes sense?
Unrelated to the concrete problem, that's the wrong place for a <br/>. It would be ignored by any webbrowser respecting the HTML specification. Don't you mean it to be inside the <li>? Or better, give it a class and let CSS give it a margin-bottom.
I am trying to conditionally build a custom list using <ui:repeat>. On every occurrence of -1 as item-value in list, I need to add a line break.
I tried to use <c:if> inside <ui:repeat> for that, but it does not seem to work. It always evaluates false.
<ul>
<ui:repeat value="#{topics.list}" var="topicId" >
<li>#{topicId}</li>
<c:if test="#{topicId eq -1}"> <br/> </c:if>
</ui:repeat>
</ul>
Is this possible?
Not with JSTL tags, no. They run during view build time, not during view render time. You can visualize it as follows: when JSF builds the view, JSTL tags run from top to bottom first and the result is a pure JSF component tree. Then when JSF renders the view, JSF components run from top to bottom and the result is a bunch of HTML. So, JSTL and JSF don't run in sync as you'd expect from the coding. At the moment your <c:if> JSTL tag tag runs, the #{topicId} variable which is set by <ui:repeat> JSF component isn't available in the scope.
Instead of using <c:if>, you need to specify the condition in the rendered attribute of the JSF component of interest. As you've actually none, you could wrap it in a <ui:fragment>.
<ul>
<ui:repeat value="#{topics.list}" var="topicId" >
<li>#{topicId}</li>
<ui:fragment rendered="#{topicId eq -1}"><br/></ui:fragment>
</ui:repeat>
</ul>
Alternatives are <h:panelGroup>
<h:panelGroup rendered="#{topicId eq -1}"><br/></h:panelGroup>
or in your specific case <h:outputText escape="false">
<h:outputText value="<br/>" escape="false" rendered="#{topicId eq -1}" />
as both also emits nothing else to the HTML output when no client side attributes are specified.
See also:
JSTL in JSF2 Facelets... makes sense?
Unrelated to the concrete problem, that's the wrong place for a <br/>. It would be ignored by any webbrowser respecting the HTML specification. Don't you mean it to be inside the <li>? Or better, give it a class and let CSS give it a margin-bottom.