In JSF what is the shortest way to output List<SomeObj> as comma separated list of "name" properties of SomeObj - jsf

I have a question about outputing a list of objects as a comma separated list in JSF.
Let's say:
public class SomeObj {
private String name;
... constructors, getters and setters ...
}
and List<SomeObj>:
List<SomeObj> lst = new ArrayList<SomeObj>();
lst.add(new SomeObj("NameA"));
lst.add(new SomeObj("NameB"));
lst.add(new SomeObj("NameC"));
to output it as a listbox I can use this code:
<h:selectManyListbox id="id1"
value="#{listHolder.selectedList}">
<s:selectItems value="#{listHolder.lst}"
var="someObj"
label="#{someObj.name}"/>
<s:convertEntity />
</h:selectManyListbox>
But what is the easiest way to output the list as is, comma seperated ? Like this:
NameA, NameB, NameC
Should I use JSTL <c:forEach/> or may be the <s:selectItems/> tag can also be used ?

Given a List<Person> persons where Person has a name property,
If you're already on Java EE 7 with EL 3.0, then use EL stream API.
#{bean.persons.stream().map(p -> p.name).reduce((p1, p2) -> p1 += ', ' += p2).get()}
If you're not on EL 3.0 yet, but have JSF 2.x at hands, then use Facelets <ui:repeat>.
<ui:repeat value="#{bean.persons}" var="person" varStatus="loop">
#{person.name}#{not loop.last ? ', ' : ''}
</ui:repeat>
Or if you're still on jurassic JSP, use JSTL <c:forEach>.
<c:forEach items="#{bean.persons}" var="person" varStatus="loop">
${person.name}${not loop.last ? ', ' : ''}
</c:forEach>
See also:
How iterate over List<T> and render each item in JSF Facelets
JSTL in JSF2 Facelets... makes sense?

use <ui:repeat> (from facelets). It's similar to c:forEach
Or pre-compute the comma-separated string in the managed bean, and obtain it via a getter.

If you can't use varStatus because you're stuck with using JSF 1.2, you can do:
<ui:repeat value="#{listHolder.lst}" var="someObj">#{someObj != listHolder.lst[0] ? ',' : ''}
#{someObj.name}</ui:repeat>
The absence of whitespace around the EL-expressions is deliberate, we don't want a space to appear there in the rendered HTML.

Related

Iterate over enum values imported by <o:importConstants>

Is it possible to iterate over ENUM in ui:repeat or c:forEach ?
I'm using o:importConstants of Omnifaces 2.5.
Example code:
<o:importConstants type="my.package.MyEnum"></o:importConstants>
<c:forEach var="icon" items="#{MyEnum}">
#{icon.toString()}
</c:forEach>
but it comes:
com.sun.faces.facelets.tag.jstl.core.MappedValueExpression$Entry#565a5787
com.sun.faces.facelets.tag.jstl.core.MappedValueExpression$Entry#6c01f0ce
com.sun.faces.facelets.tag.jstl.core.MappedValueExpression$Entry#2cd6ac37
com.sun.faces.facelets.tag.jstl.core.MappedValueExpression$Entry#7b6d8d37
com.sun.faces.facelets.tag.jstl.core.MappedValueExpression$Entry#7f8f1bb2
The <o:importConstants> converts the enum values to a Map<String, E> where the map key is the string representation of the enum name and the map value is the actual enum instance itself. What you're essentially attempting right now is printing each Map.Entry instance as string. You should actually be using its getKey() and/or getValue() methods instead.
Iterating over a Map directly is as of now only supported in <c:forEach>. See also How to use jstl foreach directly over the values of a map?
<c:forEach items="#{MyEnum}" var="entry">
Map key: #{entry.key} <br/>
Map value: #{entry.value} <br/>
</c:forEach>
The <ui:repeat> (and <h:dataTable>) only supports it from JSF 2.3 on. Until then, you'd best iterate over Map#values() instead.
<ui:repeat value="#{MyEnum.values()}" var="value">
Map value: #{value} <br/>
</ui:repeat>

JSF h:commandLink with hml entity characters, superscript etc

What is the best way of using special characters and formatting in a dynamically generated h:commandLink?
I am rendering an equation (e.g. A=π*r2) as a list of h:commandLink items, so that each symbol in the equation can be separately clicked:
JSF:
<ui:repeat value="#{eqBean.eqSymbolDisplays}" var="eqSym">
<h:commandLink value="#{eqSym.text}" styleClass="#{eqSym.styleClass}" action="#{eqBean.eqSymbolClick(eqSym)}" />
</ui:repeat>
Bean:
public String getText(){
// Return the text for a given symbol
}
The question is what the getText method should do when the symbol needs a special character, special mathematical symbol, and/or needs to be a super-script or sub-script?
Here are some specific problems/questions:
(1) How do I use the greek letter π symbol in a CommandLink? If I return π then that is what gets displayed, not the greek symbol
(2) What is the best way to do a superscript in a CommandLink? I could use a CSS style but some people say that is a bad idea, especially when the superscript implies meaning, rather than just presentation, as it does for a number raised to a power.
See :
Beware CSS for Superscript/Subcript
The answer was obvious in the end: Just replace the value attribute of the h:commandLink with a child h:outputText element that has escape="false" :
JSF:
<ui:repeat value="#{eqBean.eqSymbolDisplays}" var="eqSym">
<h:commandLink styleClass="#{eqSym.styleClass}" action="#{eqBean.eqSymbolClick(eqSym)}" >
<h:outputText value="#{eqSym.htmlText}" escape="false"/>
</h:commandLink>
</ui:repeat>

Testing JSTL String value?

I'm working with JSF and JSTL, the code above doesn't work!
<ui:repeat var="reponse" value="#{gPost.reponses}"> UserLogin : #{reponse.utilisateur.login}
<c:if test="${reponse.utilisateur.login eq 'X'}">
Utilisateur equivalent X
</c:if>
</ui:repeat>
This code iterate, i have two element to be iterated, the output is this :
UserLogin : Y
UserLogin : X
It must be :
UserLogin : Y
UserLogin : X
Utilisateur equivalent X
The tag <c:if test="${reponse.utilisateur.login eq 'X'}"> is not correct?
JSTL tags like <c:if> runs during view build time, while JSF components like <ui:repeat> runs during view render time. So, with your code given so far, the #{reponse} is not available while JSTL is running, because <ui:repeat> hasn't run. You need a normal JSF component with rendered attribute instead.
<h:panelGroup rendered="#{reponse.utilisateur.login eq 'X'}">
Utilisateur equivalent X
</h:panelGroup>
See also:
JSTL in JSF2 Facelets... makes sense?

Best approach to render UI elements based on dataType

I am trying to render richfaces and jsf UI elements dynamically based on the dataType value.
Ex : I have a enum as below
public enum DataType {
DT_LONGLONG(1), DT_STRING(2), DT_LONG(3), DT_DATE(4), DS_EXTERNALREFERENCE(5),
DT_BOOLEAN(6), DT_FLOAT(7), DT_SHORT(8);
}
Then in xhtml page while iterating through the list of my custom objects, I check for the dataType and render the UI elements accordingly as below :
<c:if test="#{meaCompPartAttr.dataType.dataType == 2}">
<h:inputText />
</c:if>
<c:if test="#{(meaCompPartAttr.dataType.dataType == 1) or
(meaCompPartAttr.dataType.dataType == 3) or
(meaCompPartAttr.dataType.dataType == 8)}">
<h:inputText onkeyup="javascript:validateField(this, '#{tpMsgs.longRegularExpression}');">
<f:validateLongRange/>
</h:inputText>
</c:if>
<c:if test="#{meaCompPartAttr.dataType.dataType == 7}">
<h:inputText onkeyup="javascript:validateField(this, '#{tpMsgs.doubleRegularExpression}');">
<f:validateDoubleRange/>
</h:inputText>
</c:if>
<c:if test="#{meaCompPartAttr.dataType.dataType == 6}">
<h:selectBooleanCheckbox />
</c:if>
<c:if test="#{meaCompPartAttr.dataType.dataType == 4}">
<rich:calendar />
</c:if>
Because of this I usually get class cast exceptions like String to Boolean or Long to String etc. I assume this is happening coz jstl and jsf code do not run in sync.
Is there any other approach to render UI elements dynamically as proposed in the above sample?
So you're iterating using <ui:repeat> or <h:dataTable> or any other JSF iterating component instead of the JSTL <c:forEach>? Either use <c:forEach> instead, or use the rendered attribute instead of <c:if>.
See also:
JSTL in JSF2 Facelets... makes sense?
How to create dynamic JSF form fields

JSF: logic based on iteration index

Pardon me for the title, that's the best my limited brain can came up this late.
So, i have a list of string, something like [abc, def, ghi].
The question: in JSF, how do I iterate the list and create a string that look like this "abc, def, ghi" (notice the commas)?
For those who have the urge to tell me that I'd better use a Java method to concatenate the string, hear this: every member of the list should be rendered as a separate commandLink.
If plain JSF it would look like:
<h:commandLink>abc</h:commandLink>, <h:commandLink>def</h:commandLink>, <h:commandLink>ghi</h:commandLink>
Assuming that #{bean.items} returns List<String> or String[], in JSF 1.x you can use JSTL c:forEach with varStatus. It gives you a handle to LoopTagStatus which has a isLast() method.
<c:forEach items="#{bean.items}" var="item" varStatus="loop">
<h:commandLink value="#{item}" /><c:if test="#{!loop.last}">, </c:if>
</c:forEach>
In Facelets as shipped with JSF 2.x, same functionality is available by ui:repeat.
<ui:repeat value="#{bean.items}" var="item" varStatus="loop">
<h:commandLink value="#{item}" />#{!loop.last ? ', ' : ''}
</ui:repeat>

Resources