我想在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会让它们通过。
问题是添加父母的名字,输入孩子信息,然后单击添加另一个孩子按钮,您刚刚输入的孩子信息将被删除。
有什么建议,我可能能够使这一切工作。似乎是一个相当简单和标准的用例。
谢谢!
第一眼看上去很好。问题症状归结为,当JSF准备应用请求值时,f.getChildrenAsList()
没有返回带有新子节点的列表。也许该方法是在提交时再次从DB重新获取列表?添加一个断点来调查它的返回值。或者视图作用域失败,导致重构bean ?向bean的构造函数添加一个断点。当你向同一个视图提交表单时,它不应该被重构。
至于使用immediate
属性,您对它们的所有使用都是完全多余的。把它们去掉。要更好地理解它的用法,请先阅读调试JSF生命周期这篇文章(没错,它是针对JSF 1.2的,但其原则与JSF2相同),然后特别阅读以下摘要:
好的,我应该在什么时候使用immediate属性?
如果还不完全清楚,这里有一个总结,其中包括可能有用的实际使用示例:
如果仅在
UIInput
(s)中设置,则过程验证阶段将在应用请求值阶段发生。使用它来对有问题的UIInput
组件进行优先级验证。当其中任何一个组件的验证/转换失败时,非直接组件将不会被验证/转换。如果仅在
UICommand
中设置,则任何UIInput
组件都将跳过应用请求值阶段直到更新模型值阶段。使用它可以跳过表单的整个处理过程。例如"Cancel"或";Back"按钮。如果在
UIInput
和UICommand
组件中都设置了该属性,则任何没有设置此属性的UIInput
组件都将跳过应用请求值阶段直到更新模型值阶段。使用它可以跳过整个表单的处理,除了某些字段(immediate)。例如:"忘记密码";