问题
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.
回答1:
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.
Analysis of your problem
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.
A working example of your code, as I understand it
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;
}
}
Things I would definitely change in your code
After the code is working I would like to state some improvements I'd make.
- Make your model a model: get rid of
@ManagedBean
and@...Scoped
annotations and make them (detached)@Entity
classes instead, delvered by your service bean; - Try to make the model as simple as possible, retaining the functionality of your application. My example uses only a list of statuses as data holders in your bean: you do not need a duplicate list of comments as it is already there for you in a
Status
object; - Do NOT use static methods inside beans, rather (pre)load nesessary data in your page action method (Servlet 3.0), or on
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; - Preload only the data you need from your data source with a service method call: if you are willing to show a limited amount of comments why fetch them from your datasource? Limit the result sets depending on what you need (remember, if you would like to implement 'view all' feature you may update your elements with ajax and load the rest). Making it work this way eliminates the need for usage of
size="..."
; - Use standard UI components or the components of the component library of your choice, which is Primefaces, so try to follow Luiggi Mendoza's suggestions.
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;
}
}
来源:https://stackoverflow.com/questions/14833968/jsf-uirepeat-size-doesnt-gets-java-bean-value