JSF view calculations - java

I know that with JSF 2, facelets is the preferred view declaration language.
Is JSP to jsf deprecated?
Anyway, I need to create a special layout so I cannot use Datatable. Instead, I have 6 divs that I use as columns in which I drop a collection of Articles.
My problem is that I have a JSF composite component, that is injected with a Collection
A:
List<Article>
object.
The component then needs to divide the size of the collection into equal pieces for each column. Then set the appropiate offset and size for each
<ui:repeat></ui:repeat>
so i end up with this
<!-- INTERFACE -->
<cc:interface>
<cc:attribute name="featuredArticles" required="true" type="java.util.List;" />
</cc:interface>
<!-- IMPLEMENTATION -->
<cc:implementation>
<div class="col">
<ui:repeat value="#{cc.attrs.featuredArticles}" var="art" offset="??" size="??">
<mycomps:article art="#{art}" />
</ui:repeat>
</div>
<div class="col">
<ui:repeat value="#{cc.attrs.featuredArticles}" var="art" offset="??" size="??">
<mycomps:article art="#{art}" />
</ui:repeat>
</div>
<div class="col">
<ui:repeat value="#{cc.attrs.featuredArticles}" var="art" offset="??" size="??">
<mycomps:article art="#{art}" />
</ui:repeat>
</div>
<div class="col">
...same here...
</div>
<div class="col">
...same here...
</div>
</cc:implementation>
So how do I calculate those offsets and sizes so that each columns iterates over a portion of the collection? Or maybe there's a better way?

You can get collection's size with fn:length and there are basic arithmetic operators in EL.
<ui:composition xmlns:fn="http://java.sun.com/jsp/jstl/core">
...
<ui:param name="size" value="#{fn:length(featuredArticles) / 6}" />
...
<ui:repeat size="#{size}">
...
</ui:composition>
Update: as to the rounding, that get tricky. In old JSP you could use JSTL <fmt:formatNumber> for this which can export to a var attribute instead of displaying it straight in the view.
<fmt:formatNumber var="size" value="${fn:length(featuredArticles) / 6}" pattern="0" />
But the JSTL fmt is not available in Facelets.
A hacky way would be to split the fractions using fn:substringBefore.
<ui:param name="size" value="#{fn:substringBefore(fn:length(featuredArticles) / 6, '.')}" />
But this always rounds down.
The best way would be to create a custom EL function. You can find an example in this answer. For JSF 2.0 you only need to replace the deprecated <param-name>facelets.LIBRARIES</param-name> by <param-name>javax.faces.FACELETS_LIBRARIES</param-name>. Finally you'll end up like as:
<ui:param name="size" value="#{x:roundUp(fn:length(featuredArticles) / 6)}" />
As a completely different alternative, you could also do this job in the constructor, init or getter of a managed bean.

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.

Struts 2 and HTML tags?

I have a form in Struts2 as follows:
<s:form >
<s:select list="#session.circleIdNameMap" label="Select Circle:"
headerKey="-1" headerValue="Select Circle"
id="selectCircleDropDown" onchange="getTspList(this.value)"></s:select>
<select id="selectTspDropDown"></select>
<s:radio list="#{'0':'Default','1':'Latest'}" label="Select Threshold type:"
name="flag" id="flag"></s:radio>
<s:submit type="button" onclick="getThresholdData();return false;" />
</s:form>
Here I am using HTML <select> tag in between, due to which there is an alignment issue. The second select tag comes up. Using simple theme everything comes in a single line.
What should I do to make alignment right?
The HTML <select> tag is used with the <option> tags together. See the example.
But you could use Struts select tag where the options are generated automatically from the list values.

Conditionally displaying a block of HTML based on presence of resource bundle key

I'm using JSF, and I have to load a bundle called Extra.
<f:loadBundle basename="com.ni.lib.extra.delivery.ExtraBundle" var="extra" />
Inside that extra variable, there's a value called downtime_notice. Now, if that value is NOT empty, I have to show a css segment with the text contained within the downtime_notice value. Something like this (of course this doesn't work):
if(extra.donwtime_notice!=''){
<div class="pnx-msg pnx-msg-warning clearfix">
<i class="pnx-msg-icon pnx-icon-msg-warning"/>
<span class="pnx-msg-content"><h:outputText value="#{extra.downtime_notice}" escape="false"/></span>
</div>
</br>
}
I can use javascript, just in case.
Any ideas? Thanks!
You can use <ui:fragment> or <h:panelGroup> to conditionally render content. You can use the empty keyword in EL to check if a variable is not null or empty. So, all with all this should do:
<ui:fragment rendered="#{not empty extra.donwtime_notice}">
<div class="pnx-msg pnx-msg-warning clearfix">
<i class="pnx-msg-icon pnx-icon-msg-warning"/>
<span class="pnx-msg-content"><h:outputText value="#{extra.downtime_notice}" escape="false"/></span>
</div>
</ui:fragment>
Or, using <h:panelGroup layout="block"> which renders a <div> already:
<h:panelGroup layout="block" styleClass="pnx-msg pnx-msg-warning clearfix" rendered="#{not empty extra.donwtime_notice}">
<i class="pnx-msg-icon pnx-icon-msg-warning"/>
<span class="pnx-msg-content"><h:outputText value="#{extra.downtime_notice}" escape="false"/></span>
</h:panelGroup>
Note that some may opt to use <f:verbatim> for the job, but this tag is deprecated since JSF2.
See also:
Conditionally displaying JSF components
Alternative to ui:fragment in JSF
Unrelated to the concrete problem, the </br> tag is invalid HTML, so I omitted it form the examples.

Assign dynamic ids to hidden fields when iterating over a collection

Is there a way to assign dynamic ids to h:inputHidden components?
EDIT1
I am trying to assign the ids inside a ui:repeat tag when iterating over a collection of elements.
It is not possible to set the ID based on the iteration value of an <ui:repeat>. But you don't need it anyway. They will by default already get dynamic and unique IDs based on the iteration index.
E.g.
<h:form id="form">
<ui:repeat value="#{bean.list}" var="item">
<h:inputHidden id="hidden" value="#{item.value}" />
</ui:repeat>
</h:form>
will generate this HTML during view render time
<form id="form" name="form">
<input type="hidden" id="form:0:hidden" name="form:0:hidden" value="item1value" />
<input type="hidden" id="form:1:hidden" name="form:1:hidden" value="item2value" />
<input type="hidden" id="form:2:hidden" name="form:2:hidden" value="item3value" />
</form>
If you want to manually control the ID, you'd need to use <c:forEach> instead, because <ui:repeat> doesn't generate multiple JSF components, but lets its children (which is a single <h:inputHidden> in the above example) generate HTML multiple times. The <c:forEach> will generate multiple JSF components which then each generate HTML only once (so you effectively end up with multiple <h:inputHidden> components in JSF component tree).
E.g.
<h:form id="form">
<c:forEach items="#{bean.list}" var="item">
<h:inputHidden id="#{item.id}" value="#{item.value}" />
</c:forEach>
</h:form>
which will basically generate this JSF component tree during view build time
<h:form id="form">
<h:inputHidden id="item1id" value="#{bean.list[0].value}" />
<h:inputHidden id="item2id" value="#{bean.list[1].value}" />
<h:inputHidden id="item3id" value="#{bean.list[2].value}" />
</h:form>
which in turn will generate this HTML during view render time
<form id="form" name="form">
<input type="hidden" id="form:item1id" name="form:item1id" value="item1value" />
<input type="hidden" id="form:item2id" name="form:item2id" value="item2value" />
<input type="hidden" id="form:item3id" name="form:item3id" value="item3value" />
</form>
See also:
JSTL in JSF2 Facelets... makes sense?
They get assigned a dynamic ID by default. You can also specify id="#{..} to customize it.
You can dynamically add any random number also (id="#{}"),but
add functionally related ids to hidden components, that will be helpful
for example if it is employee form ,you may add empid to it.

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.

Categories