Variable set by ui:param or c:set inside ui:repeat is not available outside ui:repeat - jsf

I would like to define a variable and reuse it somewhere else on the page. I'm defining variable in JSF using <ui:param> and <c:set> and resetting it in the <ui:repeat> depending on condition as follows:
<ui:param name="title" value="default value"/>
<c:set var="title2" value="default val"/>
<ui:repeat value="#{aClip.revisions}" var="revs" varStatus="revStat">
<ui:repeat value="#{revs.metadataMap.entry}" var="entryLst">
<ui:repeat value="#{entryLst}" var="entry">
<ui:repeat value="#{entry.value}" var="metaVal">
<ui:repeat value="#{metaVal.values}" var="aValue">
<ui:fragment rendered="#{metaVal.key eq 'Title'}">
rendered //this prints. condition is evaluted to true
<ui:param name="title" value="#{aValue}"/>
<c:set var="title2" value="#{aValue}"/>
title2 -- #{title2} title -- #{title} //prints
</ui:fragment>
</ui:repeat>
</ui:repeat>
</ui:repeat>
</ui:repeat>
</ui:repeat>
title2 -- #{title2} title -- #{title} //does not print value not even defualt val
I know condition is true and value is set, but when I try to use it outside loop, it doesn't evalute. It doesn't even evalute to defualt value given to variable while defining.
How is this caused and how can I solve it?

Related

JSF How to evaluate c:set only once at declaration place

I was using c:set as expression alias. Today I encountered, that c:set is evaluated everytime var is being used and also on each "invocation" it's output changes - depends on current context:
<!-- lets say composite has id "composite" -->
<ui:composition ...>
<cc:implementation>
<c:set var="compositeClientId" value="#{component.namingContainer.clientId}"/>
<!-- OUTPUTS "composite" -->
<h:outputText value="#{compositeClientId}"/>
<h:form id="form">
<!-- OUTPUTS "composite:form" -->
<h:outputText value="#{compositeClientId}"/>
</h:form>
<cc:implementation>
</ui:composition>
Is there any way, how to evaluate c:set at declaration place so in both cases it would output "composite"?

jsf make ui:param result static

I am using templating and pass some values by to use them in the template:
<ui:repeat var="entry" value="#{showEntriesBean.entries}" id="repeatId">
<ui:include src="/templates/entryTemplate.xhtml">
<ui:param name="prePath" value="/" />
<ui:param name="allowedToSee" value="#{bean.calcRandom(0, 10)}" />
</ui:include>
<br />
</ui:repeat>
I found out, that everytime I use the "allowedToSee" variable in my entryTemplate.xhtml, it recalculates its value.
Is there any way to pass the result of calcRandom in a static way? So it is ONCE calculated (when the allowedToSee value is calculated) and performs like a final number? I don't want it to be calculated everytime #{allowedToSee} is used
If you want the value to be held, you should held it somewhere.
What I would do:
1) Create a List<Integer> property.
2) When the values of the entries properties are set, call a method (preRenderEvent? #PostConstruct?) that introduces in your list as many items as there are in entries.
3) Consult that list using the varStatus attribute of ui:repeat
Little more of less, like:
<ui:repeat var="entry" value="#{showEntriesBean.entries}" id="repeatId" varStatus="status">
<ui:include src="/templates/entryTemplate.xhtml">
<ui:param name="prePath" value="/" />
<ui:param name="allowedToSee" value="#{bean.getPrecalculedRandomAt(status.index)}" />
</ui:include>
<br />
</ui:repeat>
More on the varStatus attribute: http://docs.oracle.com/javaee/6/javaserverfaces/2.0/docs/pdldocs/facelets/ui/repeat.html

c:choose with multiple c:when - fall-through switch

If i have this code on my jsf page:
<c:choose>
<c:when test="${empty example1}">
</c:when>
<c:when test="${empty example2}">
</c:when>
<c:otherwise>
</c:otherwise>
</c:choose>
it will work like java switch statement with case and break - if first when is true, second won't be test, right ?
What should i write to get "switch statement with case but without break" :
when first C:when is true something add to page and when second is true something is add to page too
You're thus basically looking for a fall-through switch. That isn't possible with <c:choose> as it represents a true if-else.... JSTL does not offer any tags for a fall-through switch.
Your best bet is to use multiple <c:if>s wherein you also check the preceding condition as an or condition.
<c:if test="#{empty example1}">
...
</c:if>
<c:if test="#{empty example1 or empty example2}">
...
</c:if>
<c:if test="#{empty example1 or empty example2 or empty example3}">
...
</c:if>
...
As you're using JSF, an alternative is using component's rendered attribute.
<h:panelGroup rendered="#{empty example1}">
...
</h:panelGroup>
<h:panelGroup rendered="#{empty example1 or empty example2}">
...
</h:panelGroup>
<h:panelGroup rendered="#{empty example1 or empty example2 or empty example3}">
...
</h:panelGroup>
...
The difference is that it's evaluated during view render time instead of during view build time. So if you were for example using this inside a <h:dataTable> based on the currently iterated row, the <c:if> wouldn't have worked the way you'd expect. See also JSTL in JSF2 Facelets... makes sense?
To eliminate the condition checking boilerplate, you could use <c:set> to create new EL variables. This works in both approaches.
<c:set var="show1" value="#{empty example1}" />
<c:set var="show2" value="#{show1 or empty example2}" />
<c:set var="show3" value="#{show2 or empty example3}" />
<h:panelGroup rendered="#{show1}">
...
</h:panelGroup>
<h:panelGroup rendered="#{show2}">
...
</h:panelGroup>
<h:panelGroup rendered="#{show3}">
...
</h:panelGroup>
...
I think it isn't possible with c:when. You can use c:if instead:
<c:if test="${empty example1}">
"example1 empty"
</c:if>
<c:if test="${empty example2}">
"example2 empty"
</c:if>
<c:if test="${not empty example1 and not empty example2}">
"both not empty"
</c:if>

Handling a ui:repeat that returns empy value

I have a ui:repeat that returns a list of entity. Is there any way to know that the returned list is empty?
<ui:repeat id="resulta" value="#{testController.testList}" var="list">
<div>list.name</div>
</ui:repeat>
something like if ui:repeat is empty then display a div saying "List is empty"
i've heard about varStatus -> Facelets repeat Tag Index
but i don't think there is something for empty list. or is there?
UPDATED
<ui:repeat id="resulta" value="#{testController.testList}" var="list">
<div>list.name</div>
<h:panelGroup rendered="#{empty list}">
list is empty!
</h:panelGroup>
</ui:repeat>
I tried to render the "list is empty!" when the list is empty but then it doesn't show.
<ui:repeat id="resulta"
value="#{testController.testList}"
var="list">
<div>
#{list.name}
</div>
</ui:repeat>
<h:panelGroup rendered="#{empty testController.testList}">
List is empty!
</h:panelGroup>
rendered is a conditional statement which only if it is true renders. In case you want to render the last h:panelGroup as a div instead of a span, consider adding layout='block' to the element.
You can display your empty list message outside your <ui:repeat> element as:
<ui:repeat id="resulta"
value="#{testController.testList}"
var="list"
rendered="#{not empty testController.testList}">
<div>
#{list.name}
</div>
</ui:repeat>
<h:panelGroup rendered="#{empty testController.testList}">
list is empty!
</h:panelGroup>

JSF Compound EL expression

I am trying to validate a inputText box based on the selection of a CheckBox as shown below.
< <h:inputText required="#{param[facesContext.externalContext.response.namespace'form:checkBoxId']}"> >.
The issue is as you see, the component Ids are dynamic, I should be able to use facesContext.externalContext.response.namespace inside the EL expression. Is there a solution to it, appreciate any suggestions.
Thanks.
Just bind the UIComponent to a page scoped property and access its getValue() method.
<h:selectBooleanCheckbox binding="#{checkbox}" />
<h:inputText required="#{not empty checkbox.value and checkbox.value}" />
As to the dynamicness, you can also go around by just giving it a fixed id.
<h:form id="form">
<h:selectBooleanCheckbox id="checkbox" />
<h:inputText required="#{not empty param['form:checkbox'] and param['form:checkbox']}" />
</h:form>
It's however only ugly when it gets lengthy.

Resources