为什么<o:validateAll>的行为与其他验证器不同?

Mar*_*ler 5 validation jsf richfaces omnifaces

我使用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>
Run Code Online (Sandbox Code Playgroud)

输入1.0和2.0之外的值并尝试切换到选项卡2以查看预期行为,由<f:validateDoubleRange>以下各项触发:显示faces-message并且第一个选项卡仍处于活动状态.

将输入留空并尝试切换到选项卡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>
Run Code Online (Sandbox Code Playgroud)

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

Bal*_*usC 2

问题有两个方面。

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

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

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

我已按照问题 322在 OmniFaces 2.6-SNAPSHOT 中修复了该问题。<o:validateAll>使用 OmniFaces 2.6 或更高版本时,为了实现不调用选项卡切换事件的所需行为,将其放置在树中的位置不再重要<rich:tabPanel>