我想在JSF中处理以下情况。我的表格包括家庭信息(姓名/地址/电话),然后是儿童信息。由于一个家庭可以有一个以上的孩子,我需要能够允许该人点击“添加更多孩子”,并且将出现另一个孩子“部分”。
这是一个简单的测试用例,我把它放在一起。
支持Bean。一个家庭有一份儿童名单。
@ViewScoped
@ManagedBean
public class TestBackingBean implements Serializable {
private Family f = new Family();
private Child childToRemove;
public TestBackingBean() {
f.addChild(new Child());
}
public Family getFamily() {
return f;
}
public void setChildToRemove(Child childToRemove) {
this.childToRemove = childToRemove;
}
public TimeZone getTimezone() {
return TimeZone.getDefault();
}
public List<Child> getChildren() {
return f.getChildrenAsList();
}
public Child getChildToRemove() {
return childToRemove;
}
public void addChild() {
f.addChild(new Child());
}
public void removeChild() {
f.removeChild(childToRemove);
}
}
这是JSF页面:
<!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:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:a4j="http://richfaces.org/a4j"
xmlns:rich="http://richfaces.org/rich"
xmlns:h="http://java.sun.com/jsf/html">
<h:head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title><ui:insert name="title" />
</title>
<link rel="stylesheet" type="text/css" href="/hcbb/css/main.css" />
</h:head>
<h:body>
<h:form>
<h:panelGroup id="parentSection">
<h:outputLabel value="Parent Name" for="parent_firstName" />
<h:inputText id="parent_firstName" requiredMessage="Required"
immediate="true" label="Parent First Name"
value="#{testBackingBean.family.firstName}">
<f:validateRequired />
</h:inputText>
<rich:message id="parent_firstNameMessage" for="parent_firstName" />
</h:panelGroup>
<h:panelGroup id="childrenSection">
<h:dataTable value="#{testBackingBean.children}" var="child">
<h:column>
<h:panelGrid id="childPanel" columns="3"
style="border:1px solid brown; padding: 5px; margin-bottom:5px; width: 600px;">
<h:outputText id="childTitle" value="Child"
style="font-weight: bold;" />
<h:outputText id="spacer" />
<a4j:commandButton id="removeBtn"
action="#{testBackingBean.removeChild}" immediate="true"
value="Remove Child" render="childrenSection"
style="float:right;" title="Remove">
<f:setPropertyActionListener
target="#{testBackingBean.childToRemove}" value="#{child}" />
</a4j:commandButton>
<h:outputLabel id="child_firstNameLbl" value="First Name" />
<h:inputText id="child_firstName" requiredMessage="Required"
immediate="true" label="Child First Name"
value="#{child.firstName}">
<f:validateRequired />
</h:inputText>
<rich:message id="child_firstNameMessage" for="child_firstName" />
<h:outputLabel id="child_lastNameLbl" value="Last Name" />
<h:inputText id="child_lastName" requiredMessage="Required"
immediate="true" label="Child Last Name"
value="#{child.lastName}">
<f:validateRequired />
</h:inputText>
<rich:message id="child_lastNameMessage" for="child_lastName" />
<h:outputLabel id="child_dobLbl" value="Birth Date" />
<h:inputText id="child_dob" label="Child Birth Date"
immediate="true" requiredMessage="Required"
value="#{child.dateOfBirth}">
<f:convertDateTime id="dobConverter" pattern="MM/dd/yyyy"
timeZone="#{testBackingBean.timezone}" />
<f:validateRequired />
</h:inputText>
<rich:message id="child_dobNameMessage" for="child_dob" />
</h:panelGrid>
</h:column>
</h:dataTable>
<a4j:commandLink id="addChildBtn" immediate="true"
render="childrenSection" action="#{testBackingBean.addChild}"
value="Add Another Child">
</a4j:commandLink>
</h:panelGroup>
</h:form>
</h:body>
</html>
问题是在添加/删除子节时保存值。如果您输入父姓名,然后输入子姓名和出生日期,然后单击添加您刚添加的孩子的字段将消失?我会认为按钮上的immediate = true,字段会让它们通过。
问题是添加父名,输入子信息并单击添加另一个子按钮,您刚刚输入的子信息将被删除。
关于我如何能够使这一切工作的任何建议。看起来像一个相当简单和有点标准的用例。
谢谢!
答案 0 :(得分:6)
乍一看看起来很好看。问题症状归结为f.getChildrenAsList()
在JSF即将应用请求值时不会返回包含新子项的列表。也许该方法在提交后再次从DB重新获取列表?添加断点以调查其retun值。或者视图范围可能失败并导致bean被重建?在bean的构造函数中添加一个断点。当您针对同一视图提交表单时,不应重建它。
至于使用immediate
属性,您对它们的所有使用都是多余的。只需删除它们。要更好地理解它的用法,请通过Debug JSF lifecycle文章(真的,它是JSF 1.2的目标,但JSF2的原理是相同的),然后特别阅读本摘要:
Okay, when should I use the immediate attribute?
如果还不完全清楚,这里有一个摘要,当它们可能有益时,可以使用真实世界的用例:
如果仅在
UIInput
(s)中设置,则过程验证阶段将在申请请求值阶段进行。使用此选项可以优先验证相关UIInput
组件的验证。当其中任何一个验证/转换失败时,将不会验证/转换非直接组件。如果仅在
UICommand
中设置,则应用请求值阶段直到更新模型值阶段将跳过任何UIInput
组件。使用此选项可跳过表单的整个处理过程。例如。 “取消”或“返回”按钮。如果同时在
UIInput
和UICommand
组件中设置,则应用请求值阶段直到更新模型值将跳过任何UIInput
组件的阶段没有设置此属性。使用此选项可以跳过对某些字段(即时)的整个表单的处理。例如。登录表单中的“忘记密码”按钮,其中包含必填但非直接的密码字段。