I am running into a weird problem when rendering JSF2 (Facelet) pages. It is the usual page that receives an id
via GET
and displays the object. The object has a List<> inside, and the problem is that sometimes that list prints nothing and sometimes I refresh and prints the list partially (all the elements but not all the information about them). It also happens with other object's attributes (some dates). I have checked with some logging and the information is obtained correctly from the DB and the object set
s the information.
I am quite sure that this is because preRenderView
is done just before the render, so the bean is by chance not available when I use c:if
or c:each
. For the second case, perhaps ui:repeat
would solve my problem?.
My questions are:
- How can I fix this?
- Is there a way in Facelets, to render f.ex. a
<section>
or<time>
(as in mydocument.xhtml
below) and don't print the empty tag if rendered computes to false? I know I can usec:if
, but rendered is recommended in Facelets. - Has the DB Javabean
Document
to beNamed
as well (besides DocumentController)?
Also, please, if there is a better way to do what I am doing (a page that receives an id
via GET
and displays the object), please advise. I am totally new to JSF.
Btw, I have discarded it is due to this problem.
DocumentController.java
@Named(value = "DocumentController")
@SessionScoped
public class DocumentController implements Serializable {
private String id;
private Document document;
/**
* @return the id
*/
public String getId() {
return id;
}
/**
* @param id the id to set
*/
public void setId(String id) {
this.id = id;
}
/**
* @return the Document
*/
public Document getDocument() {
return document;
}
/**
* @param Document the Document to set
*/
public void setDocument(Document document) {
this.document = document;
}
public void load() {
FacesContext ctx = FacesContext.getCurrentInstance();
if (ctx.isValidationFailed()) {
ctx.getApplication().getNavigationHandler()
.handleNavigation(ctx, "#{DocumentController.load}", "invalid");
return;
}
try (DataStore dst = new DataStore()) {
dst.connect();
document = dst.getDocument(id);
} catch (NoData | ConnectionError | IllegalArgumentException ex) {
ctx.getApplication().getNavigationHandler()
.handleNavigation(ctx, "#{DocumentController.load}", "invalid");
}
}
}
document.xhtml
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:utils="http://java.sun.com/jsf/composite/utils"
template="template.xhtml">
<ui:define name="content">
<f:metadata>
<f:viewParam name="id" value="#{documentController.id}" required="true"/>
<f:event type="preRenderView" listener="#{documentController.load}"/>
</f:metadata>
...
<section rendered="#{not empty documentController.document.participants}">
<utils:participants
participants="#{documentController.document.participants}
cid="example"/>
....
</ui:define>
</ui:composition>
participants.xhtml
<ui:component xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:cc="http://xmlns.jcp.org/jsf/composite"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:ui="http://java.sun.com/jsf/facelets">
<cc:interface>
<cc:attribute name="participants" type="java.util.List" required="true"/>
<cc:attribute name="cid" type="String" required="true"/>
</cc:interface>
<cc:implementation>
<table>
...
<tbody>
<c:forEach items="#{cc.attrs.participants}" var="participant">
<tr>
<td><a href="#">#{participant.name}</a></td>
<td>#{participant.lastName}</td>
<td>#{participant.role(cc.attrs.cid)}</td>
</tr>
</c:forEach>
</tbody>
</table>
</cc:implementation>
</ui:component>