动态地向JSF表单添加字段

时间:2011-09-01 17:31:09

标签: jsf jsf-2

我想在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,字段会让它们通过。

问题是添加父名,输入子信息并单击添加另一个子按钮,您刚刚输入的子信息将被删除。

关于我如何能够使这一切工作的任何建议。看起来像一个相当简单和有点标准的用例。

谢谢!

1 个答案:

答案 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组件。使用此选项可跳过表单的整个处理过程。例如。 “取消”或“返回”按钮。

  •   
  • 如果同时在UIInputUICommand组件中设置,则应用请求值阶段直到更新模型值将跳过任何UIInput组件的阶段没有设置此属性。使用此选项可以跳过对某些字段(即时)的整个表单的处理。例如。登录表单中的“忘记密码”按钮,其中包含必填但非直接的密码字段。

  •