JSF Lifecycle Issue: Component tree is built before request attributes are applied
I have a JSF 2.0 facelets view containing of a search form, an ui:repeat for displaying results, and a pager. It is backed by a request bean. The form post consists of the current page, and the search criteria. The pager shows next and previous page links depending on the position in the dataset, and the numberof results from the query with the search criteria from the form. So the component tree is dependant on request attributes. For example, I'm using the rendered attribute on the next page link like this
<h:commandLink action="#{listBean.nextPage}" 开发者_如何学Pythonrendered="#{listBean.hasNextPage}" >...
When the user clicks this link, the POST request contains the current page, and the search criteria. The problem is, that the component tree is already build in RESTORE_VIEW. In this moment, because request attributes have not been applied yet, I can neither tell on which page the user is currently, or how many records are in the dataset because i don't have the search criteria. So listBean.hasNextPage evaluates to false in this phase. This seems to cause that the CommandLink disappears from the component tree. After APPLY_REQUEST_VALUES I'm able to construct my count query. With this information and the current page, I could calculate listBean.hasNextPage. However, it doesn't seem to get evaluated again until RENDER_RESPONSE. The action does not get called in INVOKE_APPLICATION at all. Also there is no error, which is annoying.
It works when replacing rendered with c:if. c:if is only evaluated in RENDER_RESPONSE once, and the component is in the tree in the first phases by default. I don't really like it, because in the (rare, admitted) case, that the dataset count changes so that there is in fact no next page, it would still call the action and the user would be in an illegal page. Also I understand using JSTL tags in Facelets is commonly advise against. I don't know why.
Is there any trick to have rendered evaluation delayed until after APPLY_REQUEST_VALUES? There must be a way to use this attribute on properties that are dependant on the current request. Just FYI, this is a portlet 2.0 app on Liferay with the JBoss portlet bridge, but I guess it's a generic JSF problem.
Thanks in advance for any answers. I hope I'm just overlooking something, I'm still learning JSF - I can't be that hard to write a pager, right :-)
From your description it seems that you think you need the new dataset at the start of the new request (the postback), but this is not the case.
During RESTORE_VIEW
up until INVOKE_APPLICATION
you need to have the dataset available that was used to render the page on which the user has just clicked, not the one that is going to be used to render the current request.
The easiest way to achieve this is to make your backing bean @ViewScoped
and hold a reference to the dataset via an instance variable. After the postback, JSF will then automatically retain the 'old' dataset and use this for the first part of the life cycle. Then in INVOKE_APPLICATION
you have all the data to load your next page and thus set the 'new' dataset and boolean for hasNextPage
.
RENDER_RESPONSE
will then happen with the new values and will render your new page.
精彩评论