Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does <o:validateAll> behave different than other validators?

I use OmniFaces' <o:validateAll> validator to validate a number of input components. This works fine as long as I do not put it into a RichFaces <rich:tabPanel>. When I do this and leave fields blank, validation fails (as expected), but the active tab is changed, regardless of the failed validation. Other validators I tried prevent the tabPanel from switching to another tab, whenever validation fails.

What could be the reason for this?

I'm currently using OmniFaces 2.1 and RichFaces 4.5.17.Final with Mojarra 2.2.12 on Wildfly 9.0.2.

Here is the XHTML code to reproduce the problem:

<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>

Enter a value outside 1.0 and 2.0 and try switching to Tab 2 to see expected behavior, triggered by <f:validateDoubleRange>: a faces-message is displayed and the first tab is still active.

Leave input blank and try switching to Tab 2 to see behavior of <o:validateAll>: validation seems to fail (a faces-message is displayed), but Tab 2 is activated.

Update: The described behavior applies with switchType="ajax" (the default) as well as with switchType="server". In both cases, the tab-panel performs a submit of the included inputs, so from a users point of view, a tab-switch seems to be the same as a <h:commandButton> submit (technically there might be differences, I don't know the implementation details of the tab-panel).

If I perform the tab-switch via a regular <h:commandButton> with a <f:setPropertyActionListener>, the <o:validateAll> behaves the same way as the other validators, i.e. the tab-switch is not performed due to the validation error.

<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>

Note: This is just a minimalistic example showing the problematic behavior. In my real code I have not just a single component validated by <o:validateAll> and I do actually associate the input values with a backing-bean. The observed behavior is exactly the same.

like image 256
Martin Höller Avatar asked Oct 29 '22 18:10

Martin Höller


1 Answers

The problem is two-fold.

First problem is, <o:validateAll> doesn't explicitly call context.renderResponse() when validation has failed and leaves this job to JSF which will implicitly call it during validations phase when at least one input component is found invalid after <o:validateAll> has run, or otherwise during the subsequent update model values phase.

Second problem is, <rich:tabPanel> tab switch event is queued for update model values phase instead of for invoke application phase. I'm not sure why RichFaces guys designed it like that, but the consequence is that the tab switch event is fired anyway even when validation is found failed during the update model values phase only.

When you move <o:validateAll> before at least one associated input component, then JSF will implicitly call context.renderResponse() during validations phase already and therefore completely skip the update model values phase and therefore the queued <rich:tabPanel> tab switch event won't have chance to be invoked.

I have fixed it in OmniFaces 2.6-SNAPSHOT as per issue 322. When using OmniFaces 2.6 or newer, it should not anymore matter where <o:validateAll> is placed in the tree in order to achieve the desired behavior of <rich:tabPanel> tab switch event to not be invoked.

like image 185
BalusC Avatar answered Dec 23 '22 11:12

BalusC