JSF 2.0's ui:repeat tag gets the value of java bean(arraylist) as it's value property but size property doesn't. I am using the ui repeat inside of a datatable which shows statuses iteratively and ui repeat shows comments for each status. I am giving the size property of ui repeat from a java class because each status has a different number of comments. Therefore size should be decided dynamically. Here is the summary of what i've done. Model classes:
@ManagedBean
@RequestScoped
public class Comment {
private String commentAuthorName;
//getter and setter
}
This represents the Status class which has a list of comments:
@ManagedBean
@RequestScoped
public class Status {
private ArrayList<Comment> commentList;
private int numOfComments;
//getter and setter
}
This is giving an idea about StatusBean class:
@ManagedBean
@SessionScoped
public class StatusBean {
List<Status> panelList = new ArrayList<Status>();
List<Comment> commentList = new ArrayList<Comment>();
public static void process() {
panelList = StatusService.getPersonalStatus(log.getLoggeduser());//means fill list
commentList = StatusService.getPersonalComments(panelList);//gets comments via related statuses
for (int i=0; i<panelList.size(); i++) { //for each status
Status status = panelList.get(i);
for(Comment comment : commentList) { //for each comment of each status
status.setNumOfCommentsShown(1);
}
}
}
}
And view layer is sth like below. Ui repeat included in PrimeFaces DataTable to be able to show each comment for each status. I am using datatable because it has live scroll and it has to show all statuses iteratively and ui repeat looks best to show each comment for each status.
<p:dataTable liveScroll="true" value="#{StatusBean.panelList}"
var="Status" scrollable="true">
<ui:repeat var="Comment" value="#{Status.commentList}"
size="#{Status.numOfComments}"></ui:repeat>
</p:dataTable>
Debug result shows the #{Status.numOfComments} is correctly filled with expected integer but still it's not working. But if i write size=3 manually, it gives the expected result.
As far as I see there are no answer up till today, so I'll answer your question and give you some ideas on what I would have definitely changed in your stack.
I have written a code similar to yours regarding the usage of <ui:repeat>
with size
attribute specified by a managed bean property and it didn't work for me either. No matter how hard I tried to set attribute's value by EL it didn't work. Moreover, it didn't work for the simplest EL like #{5}
as well. I don't know where the problem stems from, but I think that the experiences ones here will enlighten us of why it is happening, will you?
Probably it is a glitch of the JSF <ui:repeat>
component, then we shall give rise to an issue regarding it. If it is a feature it would be nice to understand it fully.
Regarding the above code, there are many simple workarounds. In case you are so insistent on using the <ui:repeat>
component I'll provide you with the basic working example. Your view layer is backed by a JSF managed bean and two model classes. My solution uses <ui:param>
and <ui:fragment>
. Here we go.
The view:
<p:dataTable value="#{statusBean.statusesList}" var="status">
<p:column headerText="Status name">
<h:outputText value="#{status.statusName}"/>
</p:column>
<p:column headerText="Status comments">
<ul>
<ui:param name="max" value="#{status.numOfComments}"/>
<ui:repeat var="comment" value="#{status.commentList}" varStatus="statusVar">
<ui:fragment rendered="#{statusVar.index lt max}">
<li>
<h:outputText value="Author: #{comment.authorName}; comment: #{comment.description}"/>
</li>
</ui:fragment>
</ui:repeat>
</ul>
</p:column>
</p:dataTable>
The model:
public class Comment {
private String authorName;
private String description;
}
with
public class Status {
private List<Comment> commentList;
private int numOfComments;
private String statusName;
}
The managed bean:
@ManagedBean
@RequestScoped
public class StatusBean {
private List<Status> statusesList;
public StatusBean() {
Status status;
List<Status> statusesList = new ArrayList<Status>();
Comment comment;
List<Comment> commentList;
for(int s = 0; s < 10; s++) {
commentList = new ArrayList<Comment>();
for(int c = 0; c < 20; c++) {
commentList.add(new Comment("User " + (s + 1) + "-" + (c + 1), "Description for comment " + (s + 1) + "-" + (c + 1)));
}
statusesList.add(new Status(commentList, (s + 1), "Status " + (s + 1)));
}
this.statusesList = statusesList;
}
}
After the code is working I would like to state some improvements I'd make.
@ManagedBean
and @...Scoped
annotations and make them (detached) @Entity
classes instead, delvered by your service bean;Status
object;preRenderView
listener (Servlet 2.5), or in a @PostConstruct
method. Make a good choice of bean scopes. Consulting an excellent overview by BalusC would be a great starting place;size="..."
;The sample kick-off example of a managed bean follows:
@ManagedBean
@RequestScoped
public class StatusBean {
private List<Status> statusesList;
@EJB
private StatusService statusService;
@ManagedProperty(value="#{user}")
private User user;
@PostConstruct
public void init() {
statusesList = statusService.getStatuses(user);
}
public List<Status> getStatusesList() {
return statusesList;
}
}