JSF: logic based on iteration index - jsf

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>

Related

Render child component when parent component rendered property is false?

I want to create a grid like this:
Element1 Element2 Element3
Element4 Element5 Element6
I have the following code:
<ui:repeat value=#{beans.myElementList} var="element" varStatus="i">
<b:row rendered=#{i.index%3==0}>
<b:column medium-screen="4">
#{element.display}
</b:column>
</b:row>
</ui:repeat>
The result of my code:
Element1
Element4
How to solve this problem?
<b:panelGrid> to the rescue:
<ui:repeat value=#{beans.myElementList} var="element">
<b:panelGrid columns="3" size="md">
#{element.display}
</b:panelGrid>
</ui:repeat>
<b:panelGrid> is inspired by the standard <h:panelGrid>, which renders an HTML table. Similarly, <b:panelGrid> renders a table consisting of Bootstrap rows and columns. Simply put everything you want to display into the panel grid. BootsFaces automatically detects when to render a new row.
The use case I originally had in mind is a form. More often than not, such a form is a repetition of identical lines: label, input field, error message. <b:panelGrid> allows you to create tabular forms like this with minimal effort.
Also see the documentation of <b:panelGrid>.
Addition until BootsFaces 1.2.0 is released:
Looking at the documentation, I wasn't happy what I saw. So I've corrected and updated it. Until BootsFaces 1.2.0 is released, also see the documentation of the developer showcase.
Try the below code.
The first ui:repeat renders <row> for each 3 elements, the second one renders elements (within <column>) in groups of 3 elements each.
<ui:repeat value="#{beans.myElementList}" step="3" varStatus="i" >
<b:row>
<ui:repeat value="#{beans.myElementList}" var="element"
step="1" offset="#{i.index}"
size="#{i.index + 3 le beans.myElementList.size() ? i.index + 3 : beans.myElementList.size() }"
varStatus="j" >
<b:column medium-screen="4">
#{element.display}
</b:column>
</ui:repeat>
</b:row>
</ui:repeat>

jsf el expression to build methodname

Is something like that possibile to build the MethodName with a variable value?
<c:forEach value="#{db.pojo.classList}" var="v">
<c:forEach items="#{db.pojo.methodNamesList}" var="o">
<c:set var="superman" value="#{o}" />
#{v.[superman]}
</c:forEach>
</c:forEach >
... database.entity.list is a List of Generic classes.
List<?> list..
I can use the generic class if i know the Methodname.
<c:forEach value="#{db.pojo.classList}" var="v">
#{v.value}
</c:forEach >
#{v.[superman]}
Punch that period.
#{v[superman]}
That <c:set> is unnecessary, by the way.
#{v[o]}
I would only use more self-documenting variable names though. E.g.
#{bean[property]}
#{entity[field]}
See also:
Our EL wiki page

Evaluation with <c:when> in data table doesn't work

I have searched and tried but this time I'm really stuck.
I am trying to build a simple datatable (primefaces) where the cell content can be of different types. There is a holder class for each cell content that can hold different entities and I want to use < c:choose> to check and display the right entity in the entity specific way.
The code looks like:
<p:dataTable emptyMessage="" value="#{date.getThreadContent(column.propertyID)}" var="content">
<p:column>
#{content.type}
<c:choose>
<c:when test="#{content.type == 'activity'}">
#{content.activity.name}
</c:when>
<c:when test="#{content.type == 'todo'}">
#{content.activity.name}
</c:when>
<c:otherwise>
Neither activity or todo
</c:otherwise>
</c:choose>
</p:column>
</p:dataTable>
The EL evaluation doesn't work regardless if I try a boolean or String values in the bean (I'm using String value in the code above).
So each time the content is not empty, the output first displays the correct content type from #{content.type} but then together with 'Neither activity or todo'.
I can also say that this data table itself represents a cell content in a parent data table (list of entities per date) that is not visible in this code as I try to isolate the problem.
Could it be that this type of expression cannot be done in a ?
Any help is appreciated.
Use JSF rendered tags to do your conditional display logic, it removes it from the DOM completely and makes validations easier.
Refer: http://docs.oracle.com/javaee/6/tutorial/doc/bnaik.html for EL expressions
Also a good explanation is provided by BalusC here: JSTL c:if doesn't work inside a JSF h:dataTable
<p:dataTable emptyMessage="" value="#{date.getThreadContent(column.propertyID)}" var="content">
<p:column>
#{content.type}
<h:outputText value="#{content.activity.name}" rendered="#{content.type == 'activity' or content.type == 'todo'}" />
<h:outputText value="Neither activity or todo" rendered="#{content.type != 'activity' and content.type != 'todo'}" />
</p:column>
</p:dataTable>

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

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

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.

Resources