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
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.
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.
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.
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.
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.