1
votes

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
If you would like to get concrete help please do post a sscce of your code, otherwise no one will be able, or want, to answer your question. As a side note, your code shows some disrespect for Java Naming Conventions which might make some readers repulsed from answering.skuntsel
Thanks for your useful comment for a trainee. I updated my question due to your suggestions btw i don't feel OK today, sorry for mistakes.Ömer Faruk Almalı
I don't undestand what you want to achieve with an inner <ui:repeat> inside <p:dataTable>. You have other PrimeFaces components that could help you like <p:subTable> and <p:rowExpansion>.Luiggi Mendoza
What I meant is that each status element already contains list of comments and that they are entity classes or DTOs rather than managed beans (with request scopes). Next, static method of session scoped bean is a really bad idea. It would be good instead to fill the values either in post construct method, or in page action method. Also, iteration of the second lists is redundant, because there are no method calls on comment object.skuntsel
Look at the answer and enjoy JSF 'hidden' features!skuntsel

1 Answers

5
votes

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.

  1. Make your model a model: get rid of @ManagedBean and @...Scoped annotations and make them (detached) @Entity classes instead, delvered by your service bean;
  2. 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;
  3. 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;
  4. 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="...";
  5. 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;
    }

}