我使用OmniFaces' <o:validateAll>验证程序来验证许多输入组件。只要我不将其放入RichFaces <rich:tabPanel>,它就可以正常工作。当我这样做并将字段留为空白时,验证将失败(如预期的那样),但是无论验证失败如何,事件选项卡都会更改。每当验证失败时,我尝试使用的其他验证程序可防止tabPanel切换到另一个选项卡。

这可能是什么原因?

我目前在Wildfly 9.0.2上使用OmniFaces 2.1和RichFaces 4.5.17.Final和Mojarra 2.2.12。

这是重现该问题的XHTML代码:

<ui:composition xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
                xmlns:f="http://xmlns.jcp.org/jsf/core"
                xmlns:h="http://xmlns.jcp.org/jsf/html"
                xmlns:o="http://omnifaces.org/ui"
                xmlns:rich="http://richfaces.org/rich">

    <h:form id="form">

      <rich:messages />

      <rich:tabPanel id="tabPanel">

        <rich:tab id="tab1" header="Tab 1">
          <h:inputText id="myDouble" value="#{someDoubleVal}">
            <f:validateDoubleRange minimum="1.0" maximum="2.0"/>
          </h:inputText>
          <o:validateAll id="allValid" components="myDouble" message="Missing value!" />
        </rich:tab>

        <rich:tab id="tab2" header="Tab 2">
          Just another tab to switch.
        </rich:tab>

      </rich:tabPanel>

    </h:form>

</ui:composition>

输入1.0和2.0以外的值,然后尝试切换到选项卡2以查看由<f:validateDoubleRange>触发的预期行为:显示面部消息,并且第一个选项卡仍处于事件状态。

将输入留空,然后尝试切换至选项卡2以查看<o:validateAll>的行为:验证似乎失败(显示面部消息),但选项卡2被激活。

更新:所描述的行为适用于switchType="ajax"(默认设置)以及switchType="server"。在这两种情况下,选项卡面板都会执行包含的输入的提交,因此从用户的角度来看,选项卡开关似乎与<h:commandButton>提交相同(从技术上讲可能会有差异,我不知道标签面板的实现详细信息)。

如果我通过带有<h:commandButton>的常规<f:setPropertyActionListener>执行制表符切换,则<o:validateAll>的行为与其他验证程序相同,即由于验证错误而未执行制表符切换。
<rich:tabPanel id="tabPanel" activeItem="#{bb.activeTab}">
...
  <rich:tab id="tab1" name="tab1" header="Tab 1">
    ...
    <h:commandButton value="submit">
      <f:setPropertyActionListener value="tab2" target="#{bb.activeTab}" />
    </h:commandButton>
    ...
  </rich:tab>
</rich:tabPanel>

注意:这只是一个显示问题行为的简单示例。在我的真实代码中,我不仅有一个通过<o:validateAll>验证过的组件,而且实际上将输入值与backing-bean相关联。观察到的行为是完全相同的。

最佳答案

这个问题有两个方面。

第一个问题是,验证失败时<o:validateAll>不会显式调用 context.renderResponse() ,并将此作业留给JSF,它将在验证阶段隐式调用它,前提是在<o:validateAll>运行之后或者在随后的更新模型中,至少一个输入组件无效时,值(value)观阶段。

第二个问题是,<rich:tabPanel>选项卡开关事件在更新模型值阶段而不是在调用应用程序阶段排队。我不确定为什么RichFaces会这样设计,但是结果是即使在仅在更新模型值阶段验证失败时,也会触发选项卡切换事件。

当您将<o:validateAll>移至至少一个关联的输入组件之前时,JSF将已经在验证阶段隐式调用context.renderResponse(),因此将完全跳过更新模型值阶段,因此排队的<rich:tabPanel>选项卡切换事件将没有机会被调用。

我已经按照issue 322在OmniFaces 2.6-SNAPSHOT中修复了它。当使用OmniFaces 2.6或更高版本时,将<o:validateAll>放置在树中的位置不再重要,以便实现不调用<rich:tabPanel>选项卡开关事件的所需行为。

10-05 23:18