如何在JSF页面中使用<h:form>?单个表单?多个表单?嵌套表单?

50

我正在使用Facelet模板技术来布局我正在开发的JSF 2应用程序中的页面。

在我的header.xhtml文件中,primefaces要求将menubar放在h:form标签内。

<h:form>
    <p:menubar autoSubmenuDisplay="true">
        Menu Items here!
    </p:menubar>
</h:form>

因此,在我的内容页面中,我将有另一个h:form或更多。

如果我只是将h:form放在template.xhtml中,它会起作用吗?

<h:body>
    <h:form>
        <div id="top">
            <ui:insert name="header"><ui:include src="sections/header.xhtml"/></ui:insert>
        </div>
        <div>
            <div id="left">
                <ui:insert name="sidebar"><ui:include src="sections/sidebar.xhtml"/></ui:insert>
            </div>
            <div id="content" class="left_content">
                <ui:insert name="content">Content</ui:insert>
            </div>
        </div>
        <div id="bottom">
            <ui:insert name="footer"><ui:include src="sections/footer.xhtml"/></ui:insert>
        </div>
    <h:form>
</h:body>

我实际上在考虑一个需要在页面中使用多个h:form的用例。

谢谢


在模板页面上放置表单并不是一个好主意。我们需要将组件与表单包围起来,我认为表单应该放在组件所在的位置。 - Bhesh Gurung
许多 PrimeFaces 组件在不使用任何 ajax 功能的情况下也可以在没有表单的情况下工作(可以在子组件上使用 ajax="false")。不确定 MenuBar 是否适用,但例如 TabView 是可以使用的。 - djmj
我觉得现在已经太晚了。但是今天早上我遇到了同样的问题。我被迫使用一个包含单个表单的模板。如果您使用Primefaces,它提供了一个很好的解决方案来解决这个问题: fragment - reda la
2个回答

91

您可以在JSF页面中安全地使用多个表单。这与使用普通的HTML没有区别。

在HTML中,嵌套<form>元素是无效的。由于JSF只生成一堆HTML,因此在JSF中也没有区别。因此,在JSF中嵌套<h:form>也是无效的。

<h:form>
    ...
    <h:form> <!-- This is INVALID! -->
        ...
    </h:form>
    ...
</h:form>

提交嵌套表单时,浏览器的行为是未指定的。它可能按照您的期望工作,也可能不会。例如,它可能只是刷新页面而不调用bean操作方法。即使您通过dom操作(或者例如使用PrimeFaces的appendTo="@(body)")将嵌套表单(或包含它的组件)移动到父表单之外,它仍然无法正常工作,并且在加载页面时不应该有嵌套表单。关于哪些表单需要保留,拥有单个“上帝”<h:form>实际上是一种不好的做法。因此,最好从主模板中删除外部<h:form>,并让headersidebarcontent等各个部分定义自己的<h:form>。多个并行表单是有效的。
<h:form>
    ...
</h:form>
<h:form> <!-- This is valid. -->
    ...
</h:form>

每个表单必须有一个明确的责任。例如:登录表单、搜索表单、主表单、对话框表单等。当您提交某个表单时,不希望不必要地处理所有其他表单/输入。
请注意,当您提交某个表单时,其他表单不会被处理。因此,如果您打算无论如何处理另一个表单的输入,则存在设计问题。可以将其放在同一表单中,或者投入一些丑陋的JavaScript技巧,将所需信息复制到包含提交按钮的表单的隐藏字段中。
在特定表单内,您可以使用ajax来限制输入的处理范围。例如:<f:ajax execute =“@ this”>仅处理(提交/转换/验证/调用)当前组件,而不是同一表单中的其他组件。这通常用于需要动态填充/呈现/切换同一表单中的其他输入的用例,例如:依赖下拉菜单、自动完成列表、选择表等。
另请参见:

1
@BalusC: 你能否进一步澄清,即使我在 p:remoteCommandprocess 属性中明确指定要处理的所有字段,所有输入字段是否都会被提交? - Rajat Gupta
2
@user:肯定所有表单字段都已提交。process是服务器端的事情。您可以通过查看HTTP流量轻松了解它。 - BalusC
嗨@BalusC:如果我遇到这种情况怎么办(请看这个问题)http://stackoverflow.com/questions/19091230/ - Kishor Prakash
1
在某些PrimeFaces组件上,您可以使用appendTo="@(body)"来处理嵌套表单的情况。最终的HTML将附加在页面底部。对于对话框非常有用。也许它可以通过将表单包围在面板中来实现。 - djmj
1
@BalusC 如果您使用PrimeFaces向导时遇到这种情况,您会怎么做?使用向导,您需要有一个<h:form>。如果我想在每个选项卡上都有另一个表单,该怎么办?http://stackoverflow.com/questions/32468421/how-to-prevent-primeface-wizard-next-button-activate-client-validations/32486192?noredirect=1#comment52883149_32486192 - Erick
显示剩余4条评论

-1
我曾经被这个问题困扰了一段时间。我将一系列独立的表单转换为模板,也就是说,不再像以前那样调用一个包含多个表单的xhtml文件,而是在父模板中调用那些之前通过ui:include包含在内的xhtml页面,然后使用ui:content进行捕获。

你能给一个代码示例说明一下你在这里做的事情吗?这样可以帮助其他人。 - Guillaume Racicot
是的,我会的。我的情况是这样的: - emm
我只是验证所有表格都是线性的而不是嵌套的。对我来说有点难以证明。这个概念是某些表格由于某种目的而相关联,我的建议是应该使用模板来分组这些表格。每个表格独立检索,由菜单管理。很多时候我在同一个xhtml中尝试了一系列独立的表格,在我的情况下commandLink或commandButton总是失败的。不确定我的结果是否适用于所有情况,我正在使用Windows 10、Netbeans/GlassFish。 - emm

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接