JSF JSTL problem with nested forEach - java

Inside a nested foreach, accessing the same variable is returning different values. This happens when the page is reloaded, not on first load.
<ui:composition
xmlns="http://www.w3.org/1999/xhtml"
(...)
xmlns:c="http://java.sun.com/jstl/core"
xmlns:h="http://java.sun.com/jsf/html">
(...)
<c:forEach items="#{controller.availableTransitions}" var="transition">
<c:forEach items="#{transition.availableTransitions}" var="transitionItem">
<h:outputText value="1_#{transitionItem.name} 2_#{transitionItem.name}" />
3_#{transitionItem.name} 4_#{transitionItem.name}
</c:forEach>
</c:forEach>
</ui:composition>
After page reload, transitionItem.Name returns the correct value for 3 and 4, and different values for 1 and 2. Maybe a JSF-JSTL integration problem?

I see that you are using Facelets.
Maybe you can try to replace your <c:forEach> by <ui:repeat>...
The code will then become:
<ui:composition
xmlns="http://www.w3.org/1999/xhtml"
(...)
xmlns:c="http://java.sun.com/jstl/core"
xmlns:h="http://java.sun.com/jsf/html">
(...)
<ui:repeat value="#{controller.availableTransitions}" var="transition">
<ui:repeat value="#{transition.availableTransitions}" var="transitionItem">
<h:outputText value="1_#{transitionItem.name} 2_#{transitionItem.name}" />
3_#{transitionItem.name} 4_#{transitionItem.name}
</ui:repeat>
</ui:repeat>
</ui:composition>

In general, I try to use ui:repeat most of the time. When I was having c:set issues, I found this blog, which was very helpful and may apply in your case also.
https://rogerkeays.com/jsf-c-foreach-vs-ui-repeat

Found a workaround, by getting rid of the inner forEach loop, thus returning a linear list from the controller.

Related

JSF <ui:include /> Recursion Causes java.lang.StackOverflowError

I have, what I would assume, is a pretty common use case. We're rendering a simple "Comments" page using JSF on Wildfly 10.0. Each comment may have a parent comment, and child comments underneath it. Since there's no way to know ahead of time what the structure is, we'd like to create a JSF fragment and <ui:include /> it recursively to render the contents. It would look something like this...
Main page:
<ul class="comments>
<ui:repeat value="#{myObj.comments}" var="comment">
<ui:include src="/WEB-INF/fragments/comment.xhtml">
<ui:param name="comment" value="#{comment}" />
</ui:include>
</ui:repeat>
</ul>
Comment Fragment:
<li><h:outputText value="#{comment.text}">
<ui:fragment rendered="#{not empty comment.childComments}">
<ul class="comments">
<ui:repeat value="#{comment.childComments}" var="comment">
<ui:include src="/WEB-INF/fragments/comment.xhtml">
<ui:param name="comment" value="#{comment}" />
</ui:include>
</ui:repeat>
</ul>
</ui:fragment>
</li>
However, when I run this code, the recursion seems to cause java.lang.StackOverflowError, regardless of how many items there are. Additionally, we see a javax.servlet.ServletException saying, "Could not Resolve Variable [Overflow]"
Is there a reason why this recursive call results in this Exception? Is there a better way to accomplish this? I've tried using <c:forEach /> to iterate over the comments, however when I do this it does not appear to work in JSF. I've tried both the http://xmlns.jcp.org/jsp/jstl/core and http://java.sun.com/jsp/jstl/core namespaces for the taglib, but the <c:forEach /> tag doesn't seem to iterate over my objects. (That is, nothing is being rendered to the page)
Any help you can give would be GREATLY appreciated.

JSF Component IDs ignored when dynamically generating Views

I ran into a bit of a problem.
I generate Views dynamically by iterating a list of strings via the c:forEach tag
and then including them via the facelets include tag.
This works fine for building the layout but shows some strange behaviour.
I have a primefaces tabview containing 2 tabs.
For the first Tab (the one that gets initially displayed) the component id is set (eg. tabview:categoryTab) but that's not the case for e.g. the second tab, here I only get tabview: for the component id (but it actually should be tabview:usrTab)
Why does JSF override the id I set for the second Tab? Am I missing some crucial information from the spec?
I use JSF 2 with Primefaces 3.6 (snapshot build)
(And yes, I use the snapshot build on purpose and have tested this with stable PF releases as well but the same behaviour occurs)
edit
Code:
admin.xhtml
<ui:composition template="/templates/commonLayout.xhtml">
<ui:define name="content">
<p:panel id="parentPanel">
<h:outputText value="Verwaltung" />
<br />
<p:tabView id="tabview">
<!-- insert marker -->
<c:forEach items="#{adminTabs}" var="tab">
<ui:include src="#{tab}" />
</c:forEach>
</p:tabView>
</p:panel>
</ui:define>
</ui:composition>
catTab.xhtml
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:p="http://primefaces.org/ui"
xmlns:ui="http://java.sun.com/jsf/facelets">
<p:tab title="Categories Tab" id="catTab">
....
</p:tab>
</ui:composition>
usrTab.xhtml
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:p="http://primefaces.org/ui"
xmlns:ui="http://java.sun.com/jsf/facelets">
<p:tab title="Users Tab" id="usrTab">
....
</p:tab>
</ui:composition>
testTab.xhtml
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:p="http://primefaces.org/ui"
xmlns:ui="http://java.sun.com/jsf/facelets">
<p:tab title="TestTab" id="testTab">
....
</p:tab>
</ui:composition>
ContentProvider.java
public class ContentProvider {
....
#Produces
#Named("adminTabs")
public List<String> getTabs(){
List<String> components = new ArrayList<String>();
components.add("/templates/tabs/catTab.xhtml");
components.add("/templates/tabs/usrTab.xhtml");
components.add("/templates/tabs/testTab.xhtml");
return components;
}
....
}
This gets generated:
<ul class="ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" role="tablist">
<li class="ui-state-default ui-tabs-selected ui-state-active ui-corner-top" aria-expanded="true" role="tab">
Categories
</li>
<li class="ui-state-default ui-corner-top" aria-expanded="false" role="tab">
TestTab
</li>
<li class="ui-state-default ui-corner-top" aria-expanded="false" role="tab">
Benutzer und Rollen
</li>
</ul>
So, to reiterate: Only the id for the first tab is retained, the ids for the other tabs are generated despite being set in the xhtml code...
I ran into something very similar with Richfaces 4 and JSF 2. I managed to hack around it by including an EL expression in the id attribute. For me
<h:form id="staticName">
was being rendered into
<form id="j_idblah>
but once I did
<h:form id="#{_objectInContext}">
it began rendering properly. Pretty hacky, but for now it'll work. Good luck!!
I ran into the same problem when including facelets with a c:forEach loop.
What worked for me was specifying the Ids as EL-Constants: id="#{'address_street'}"

List Iterate in paragraph form in JSF page

I want to iterate list in paragraph form in JSF page...
for E.g.
I have list and i want to iterate it's value as
like
list<String>={'test1','test2','test3'}
I want JSF output as
test1:..test2:...test3...
how to achieve this ?
Hope this is helpful.
<html xmlns:ui="http://java.sun.com/jsf/facelets">
<ui:repeat var="test" value="#{someClass.methodThatReturnList}">
#{test}:
</ui:repeat>
JSF way is h:dataTable but since you want it just to be displayed in one line you can go with JSTL
<c:forEach items="${yourBean.youeLIst}" var="para">
<c:out value="${para}"/>
</c:forEach>

Resolving facelets components at runtime

do you know a way to select a different facelets component at runtime?
I've got some of code similar to this:
<s:fragment rendered="#{r== 'case1'}">
<div>
<ui:include src="case1.xhtml" />
</div>
</s:fragment>
<s:fragment rendered="#{r== 'case2'}">
<div>
<ui:include src="case2.xhtml" />
</div>
</s:fragment>
I'd like to write
<ui:include src="#{r}.xhtml" />
Thanks.
Your solution should work OK - the src attribute can be a literal or an EL expression. You might want to make the expression use a managed bean property or resolve it through a function. That way, you can ensure that it is never null (you could return a reference to an empty page if it was). You'll probably get a 404 error if #{r} resolves to null.
<ui:include src="#{myfn:resolveNotNull(r, 'pageIfRIsNull')}.xhtml" />
Not sure. An alternative though would be to use a template with a ui:insert and then direct to case1 or case2 which use ui:define programatically.
It is possible to have selective use of ui:include with other JSF components. Example:
<h:panelGroup rendered="#{!menuMBean.passwordResetRequired}">
<ui:include src="homeNormal.xhtml" />
</h:panelGroup>

conditional check in c:if always fails

The c:if test always fails for me and it never gets inside the loop. I am using the following namespaces
xmlns:fn="http://java.sun.com/jsp/jstl/functions"
xmlns:c="http://java.sun.com/jstl/core"
The string ('array') to be split is "Tom and Jerry are GAP1 friends"
<s:decorate template="/layout/display-text.xhtml">
<c:set var="array" value="#{_mybean.value}"/>
<c:set var="space" value="#{fn:split(array, ' ')}"/>
<c:set var="len" value="#{fn:length(space)}"/>
<h:outputText value="total length = #{len}"/><br/>
<c:forEach begin="0" end="5" var="index">
<h:outputText value="index = #{index}, value = #{space[index]}"/><br/>
<c:set var="val" value="#{space[index]}"/>
<c:if test="#{fn:startsWith(val, 'GAP')}">
<h:outputText value="Found keyword parameter GAP" /><br/>
</c:if>
</c:forEach>
</s:decorate>
The JSTL core URI is invalid. As per the JSTL TLD it should be (note the extra /jsp):
xmlns:c="http://java.sun.com/jsp/jstl/core"
That said, mixing JSF with JSTL is never been a good idea. It won't always give results as you'd expect because they doesn't run in sync as you would expect from the coding. It's more that JSP/JSTL runs from top to bottom first and then hands over the produced result to JSF to process further from top to bottom again. That would cause some specific constructs to fail. Better use pure JSF components/attributes instead.
Instead of c:forEach, rather use Seam's a4j:repeat or Facelets' ui:repeat and instead of c:if make use of the rendered attribute of the JSF component which has to be toggled to show/hide. Instead of all that JSTL c:set, write appropriate code logic in managed bean constructor or action method or getter.
The JSTL functions (fn) taglib is however still highly valuable in JSF. You can keep using it.

Categories