Resolving facelets components at runtime - java

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>

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.

Primefaces / JSF: selectOneMenu value is not set, ajax listener not called

I am using Primefaces and JSF to develop this frontend. My issue is that one of my selectonemenus never sets its value binding, "selectedGroup", so the second dropdown is never populated. My backing bean is being called to "update" the second selectonemenu, but the listener of that ajax is not called, nor is selectedGroup ever set. This code is effectively identical to the Showcase for "Select". I even verified that the showcase code works from scratch (which i did not doubt), but fail to see how my situation is any different from that example.
Other stackoverflow questions on this topic indicate that something was left out, but none of those suggestions matched my issue.
I have two selectOneMenus, like so.
<h:form id="outerForm">
<p:panel id="outerPanel">
<p:panelGrid id="outerPanelGrid">
<h:outputLabel for="groupSelection" value="Group: "/>
<p:selectOneMenu id="groupSelection" value="#{myBean.selectedGroup}" >
<p:ajax update="commandSelection"
listener="#{myBean.handleGroupSelection}" />
<f:selectItem itemLabel="---Please Select Group---" itemValue=""/>
<f:selectItems var="group" value="#{myBean.groups}"
itemLabel="#{group.name}" itemValue="#{group.name}" />
</p:selectOneMenu>
<h:outputLabel for="commandSelection" value="Command: "/>
<p:selectOneMenu id="commandSelection" value="#{myBean.command}">
<f:selectItems value="#{myBean.commandStringsList}"/>
</p:selectOneMenu>
</p:panelGrid>
</p:panel>
</h:form>
This page is being displayed in the "center" portion of my layout template like so..
<ui:define id="content" name="content">
<p:panel id="contentPanel" style="float:left; border:none">
<ui:include src="#{anotherBean.currentView}.xhtml"/>
</p:panel>
</ui:define>
The backing bean DOES use some data classes to contain some of the data which is populated, but I thought i was doing everything correct to map it into the view. For the most part, I am using Strings, though.
Does anyone see what I am missing? At the very least, is this xhtml valid?
I should also mention that this page was working before I created and used a template. Basically, I was rendering it in a tab of a tabview using ui:include in the body of index.xhtml. Though I did not notice initially, this page stopped working sometime after I incorporated the template (poor testing on my part, I know).
<f:selectItems var="group" value="#{myBean.groups}"
itemLabel="#{group.name}" itemValue="#{group.name}" />
you can't specify selectItems this way. translation has to be bidirectional. use a converter!
<f:selectItems var="group" value="#{myBean.groups}"
itemLabel="#{group.name}" itemValue="#{group}"
converter="groupConverter"/>

JSF: conditionally render a list item (<li>)

I just inherited a project implemented in JSF. I have the following code which looks fine in Chrome, but Firefox renders the borders on the "empty" list items:
<ul>
<li><a href="/home">Home</li>
<li>
<s:link view="/signup.xhtml" rendered="#{someCondition}">Sign Up</s:link>
</li>
<!-- etc... -->
</ul>
Which ends up looking like:
Is there a JSF tag to conditionally render the <li> ?
If you do it as in #CoolBeans example, you will get a <span> around your <li>. In some cases it might disrupt your layout, besides you don't really want an extra tag under <ul>. To get rid of it, use <ui:fragment rendered="#{condition}" /> around your item instead of <h:panelGroup>.
Also you can use style attribute to hide an item:
<li style="display: #{condition ? 'list-item' : 'none'};" />
No li is vanilla html, not a jsf component.
You can hack it by putting a <h:panelGroup /> around the li element and setting the rendered property on it.
ie.
<h:panelGroup rendered="#{someCondition}">
<li>
<s:link view="/signup.xhtml">Sign Up</s:link>
</li>
</h:panelGroup>
Another option is to use <f:verbatim rendered="#{someCondition}" >, but keep in mind that it has been deprecated in JSF 2.0.
You could also use the core JSTL library:
<c:if test="#{someCondition}">
<li>
<s:link view="/signup.xhtml">Sign Up</s:link>
</li>
</c:if>
I think using this core tag makes the code easier to understand than using the panelGroup tag.

What is the analog of jsp .tag-files in jsf or how to avoid coping and pasting jsf/facelets code?

I think the title is clear enough so I only add an example of typical situation.
First block of code:
<div id="mailpanel">
<h:panelGroup id="sendmailpane" styleClass="sendmailpane" layout="block"
rendered="#{userReports.reportRendered}">
<o:inputTextarea promptText="#{msg['mail.listrules']}" promptTextStyle="color: #333"
value="#{userReports.mailingList}" styleClass="maillist"/>
<br/>
<h:commandLink id="sendlink" value="#{msg['mail.sendLink']}"
action="#{userReports.sendMail}"/>
</h:panelGroup>
</div>
Second (copied) block of code:
<div id="mailpanel">
<h:panelGroup id="sendmailpane" styleClass="sendmailpane" layout="block"
rendered="#{projectReports.reportRendered}">
<o:inputTextarea promptText="#{msg['mail.listrules']}" promptTextStyle="color: #333"
value="#{projectReports.mailingList}" styleClass="maillist"/>
<br/>
<h:commandLink id="sendlink" value="#{msg['mail.sendLink']}"
action="#{projectReports.sendMail}"/>
</h:panelGroup>
</div>
As you can see both blocks of code are almost similar but each of them uses different backing bean (but even beans have a superclass and all used in this example methods are actually methods of that superclass).
<ui:include src="commonFile.jsp">
<ui:param name="reportsBean" value="#{projectReports}" />
</ui:include>
and in the commonFile.jsp you have:
<h:commandLink id="sendlink" value="#{msg['mail.sendLink']}"
action="#{reportsBean.sendMail}" />
You cannot, alas, specify what params exactly are to be included. That's why I'm using the following practice: whenever you add a parameter, you put a comment ontop of the commonFile.jsp stating the name, the type and the required/optional. For example:
<!-- param: reportsBean, required -->
<!-- param: showLegend, optional, default: false, type: boolean -->
In JSP, you can use custom tags for this. In Facelets, you can use templating or the JSF 2.0 composite components for this.

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