我猜这是构建与渲染时间的问题。 我是评论部分,是评论树。一切正常......除了一些注释之外没有调用bean setter。
所以我的理解是:
使用ui时:重复复合组件在构建时包含一次,然后为每个项目呈现其适当的值。它为什么不起作用?没有头绪。
当使用c:forEach时,复合组件被多次集成,然后在渲染时,当要填充commandButton操作时,该项将丢失。
以下是重现错误的完整工作示例:
WorkingTest Bean :
import java.io.Serializable;
import javax.faces.view.ViewScoped;
import javax.inject.Named;
@Named
@ViewScoped
public class WorkingTest implements Serializable{
private static final long serialVersionUID = 1L;
private Post topNode;
private String replyContent;
private int counter;
public WorkingTest(){
topNode = new Post();
Post p1 = new Post(1, "reply here works");
p1.getReplies().add(new Post(3, "Reply to this comment <b style=\"color:red\">doesn't works</b>, the content of the comment is null"));
Post p2 = new Post(1, "reply here works");
topNode.getReplies().add(p1);
topNode.getReplies().add(p2);
counter = 6;
}
public void addReply(Post post){
post.getReplies().add(new Post(counter, replyContent));
replyContent = "";
counter++;
}
public Post getTopNode() {
return topNode;
}
public void setTopNode(Post topNode) {
this.topNode = topNode;
}
public String getReplyContent() {
return replyContent;
}
public void setReplyContent(String replyContent) {
System.out.println("settting reply content");
this.replyContent = replyContent;
}
}
发布课程:
import java.util.ArrayList;
import java.util.List;
public class Post {
private long idpost;
private String content;
private List<Post> replies = new ArrayList<Post>();
public Post(){}
public Post(long id, String content){
this.content = content;
this.idpost = id;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public List<Post> getReplies() {
return replies;
}
public void setReplies(List<Post> replies) {
this.replies = replies;
}
public long getIdpost() {
return idpost;
}
public void setIdpost(long id) {
this.idpost = id;
}
}
Test.xhtml :
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:c="http://java.sun.com/jsp/jstl/core">
<h:head>
<title>
<ui:insert>Test</ui:insert>
</title>
</h:head>
<h:body id="whole">
Refresh your page between tries, you will see that for some comments the
value of the comment doesn't appear.
Because of a bug in mojarra the viewstate is lost after ajax request, that is why u gotta refresh.
see http://balusc.omnifaces.org/2011/09/communication-in-jsf-20.html#AutomaticallyFixMissingJSFViewStateAfterAjaxRendering if you want more info
<h:panelGroup id="replies">
<div class="replies">
<ui:include src="pv.xhtml" >
<ui:param name="node" value="#{workingTest.topNode.replies}"/>
<ui:param name="count" value="8"/>
<ui:param name="backgroundVar" value="0"/>
<ui:param name="isFirst" value="true"/>
</ui:include>
</div>
</h:panelGroup>
</h:body>
</html>
pv.xhtml :
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:p="http://primefaces.org/ui"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:my="http://xmlns.jcp.org/jsf/composite/cc">
<ui:repeat value="#{node}" var="forumPost">
<div style="padding: 0.4rem; border: 1px solid grey; margin-bottom: #{isFirst ? '1rem' : '0' }">
<h:panelGroup id="c">
<!-- comment content -->
<div class="replyContent">
<h:outputText value="#{forumPost.content}" escape="false"/>
</div>
<!-- reply block -->
<div class="replyAuthor" id="r-#{forumPost.idpost}">
<my:commentForm value="#{workingTest.replyContent}" actionMethod="#{workingTest.addReply(forumPost)}"/>
</div>
<!-- reply block end -->
</h:panelGroup>
<!-- Replies -->
<c:if test="#{count gt 0}">
<ui:include src="pv.xhtml">
<ui:param name="node" value="#{forumPost.replies}"/>
<ui:param name="count" value="#{count-1}"/>
<ui:param name="backgroundVar" value="#{backgroundVar+1}" />
<ui:param name="isFirst" value="false" />
</ui:include>
</c:if>
</div>
</ui:repeat>
</ui:composition>
commentForm.xhtml (复合组件)
<ui:composition
xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:cc="http://xmlns.jcp.org/jsf/composite"
xmlns:my="http://xmlns.jcp.org/jsf/composite/cc">
<cc:interface>
<cc:attribute name="value" type="java.lang.String" required="true" />
<cc:attribute name="actionMethod" method-signature="void action()"/>
</cc:interface>
<cc:implementation>
<h:form>
<h:inputTextarea value="#{cc.attrs.value}"/>
<div class="replyBtn">
<h:commandButton value="Reply" action="#{cc.attrs.actionMethod}">
<f:ajax execute="@form" render="replies"/>
</h:commandButton>
</div>
</h:form>
</cc:implementation>
</ui:composition>
对于有效的评论以及那些不需要http表格数据的评论。但是对于JSF生命周期,验证者不会被调用那些不工作和更新阶段的人不会调用setter:
工作:
20:34:35,120 INFO [stdout] (default task-41) START PHASE RESTORE_VIEW 1
20:34:35,228 INFO [stdout] (default task-41) END PHASE RESTORE_VIEW 1
20:34:35,229 INFO [stdout] (default task-41) START PHASE APPLY_REQUEST_VALUES 2
20:34:35,229 INFO [stdout] (default task-41) before msg The form component needs to have a UIForm in its ancestry.
20:34:35,240 INFO [stdout] (default task-41) END PHASE APPLY_REQUEST_VALUES 2
20:34:35,240 INFO [stdout] (default task-41) START PHASE PROCESS_VALIDATIONS 3
20:34:35,240 INFO [stdout] (default task-41) before msg The form component needs to have a UIForm in its ancestry.
20:34:35,245 INFO [stdout] (default task-41) DummyConverter getAsObject
20:34:35,245 INFO [stdout] (default task-41) FieldsNotTooShort: validate
20:34:35,252 INFO [stdout] (default task-41) END PHASE PROCESS_VALIDATIONS 3
20:34:35,252 INFO [stdout] (default task-41) START PHASE UPDATE_MODEL_VALUES 4
20:34:35,253 INFO [stdout] (default task-41) before msg The form component needs to have a UIForm in its ancestry.
20:34:35,257 INFO [stdout] (default task-41) setting 5555555555555555555555
20:34:35,261 INFO [stdout] (default task-41) END PHASE UPDATE_MODEL_VALUES 4
无效:
20:39:12,312 INFO [stdout] (default task-30) START PHASE RESTORE_VIEW 1
20:39:12,432 INFO [stdout] (default task-30) END PHASE RESTORE_VIEW 1
20:39:12,432 INFO [stdout] (default task-30) START PHASE APPLY_REQUEST_VALUES 2
20:39:12,432 INFO [stdout] (default task-30) before msg The form component needs to have a UIForm in its ancestry.
20:39:12,436 INFO [stdout] (default task-30) END PHASE APPLY_REQUEST_VALUES 2
20:39:12,436 INFO [stdout] (default task-30) START PHASE PROCESS_VALIDATIONS 3
20:39:12,437 INFO [stdout] (default task-30) before msg The form component needs to have a UIForm in its ancestry.
20:39:12,440 INFO [stdout] (default task-30) END PHASE PROCESS_VALIDATIONS 3
20:39:12,441 INFO [stdout] (default task-30) START PHASE UPDATE_MODEL_VALUES 4
20:39:12,441 INFO [stdout] (default task-30) before msg The form component needs to have a UIForm in its ancestry.
20:39:12,444 INFO [stdout] (default task-30) END PHASE UPDATE_MODEL_VALUES 4
lifecyclelistener:
public class LifeCycleListener implements PhaseListener {
public PhaseId getPhaseId() {
return PhaseId.ANY_PHASE;
}
public void beforePhase(PhaseEvent event) {
System.out.println("START PHASE " + event.getPhaseId());
List<FacesMessage> msgs = event.getFacesContext().getMessageList();
for (FacesMessage msg : msgs) {
System.out.println("before msg " + msg.getSummary() + " :: " + msg.getDetail());
}
}
public void afterPhase(PhaseEvent event) {
System.out.println("END PHASE " + event.getPhaseId());
}
}