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

时间:2016-10-10 14:40:59

标签: 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>

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

将输入留空并尝试切换到选项卡2以查看<o:validateAll>的行为:验证似乎失败(显示了face-message),但Tab 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>验证的单个组件,而且我实际上将输入值与支持bean相关联。观察到的行为完全相同。

1 个答案:

答案 0 :(得分:2)

问题是双重的。

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

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

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

我已根据issue 322在OmniFaces 2.6-SNAPSHOT中修复了它。当使用OmniFaces 2.6或更高版本时,为了实现<rich:tabPanel>制表符切换事件的所需行为不被调用,不应再将<o:validateAll>置于树中的位置。